aboutsummaryrefslogtreecommitdiff
path: root/webrtc/system_wrappers/source
diff options
context:
space:
mode:
authorChih-hung Hsieh <chh@google.com>2015-12-01 17:07:48 +0000
committerandroid-build-merger <android-build-merger@google.com>2015-12-01 17:07:48 +0000
commita4acd9d6bc9b3b033d7d274316e75ee067df8d20 (patch)
tree672a185b294789cf991f385c3e395dd63bea9063 /webrtc/system_wrappers/source
parent3681b90ba4fe7a27232dd3e27897d5d7ed9d651c (diff)
parentfe8b4a657979b49e1701bd92f6d5814a99e0b2be (diff)
downloadwebrtc-a4acd9d6bc9b3b033d7d274316e75ee067df8d20.tar.gz
Merge changes I7bbf776e,I1b827825
am: fe8b4a6579 * commit 'fe8b4a657979b49e1701bd92f6d5814a99e0b2be': (7237 commits) WIP: Changes after merge commit 'cb3f9bd' Make the nonlinear beamformer steerable Utilize bitrate above codec max to protect video. Enable VP9 internal resize by default. Filter overlapping RTP header extensions. Make VCMEncodedFrameCallback const. MediaCodecVideoEncoder: Add number of quality resolution downscales to Encoded callback. Remove redudant encoder rate calls. Create isolate files for nonparallel tests. Register header extensions in RtpRtcpObserver to avoid log spam. Make an enum class out of NetEqDecoder, and hide the neteq_decoders_ table ACM: Move NACK functionality inside NetEq Fix chromium-style warnings in webrtc/sound/. Create a 'webrtc_nonparallel_tests' target. Update scalability structure data according to updates in the RTP payload profile. audio_coding: rename interface -> include Rewrote perform_action_on_all_files to be parallell. Update reference indices according to updates in the RTP payload profile. Disable P2PTransport...TestFailoverControlledSide on Memcheck pass clangcl compile options to ignore warnings in gflags.cc ...
Diffstat (limited to 'webrtc/system_wrappers/source')
-rw-r--r--webrtc/system_wrappers/source/Android.mk65
-rw-r--r--webrtc/system_wrappers/source/OWNERS6
-rw-r--r--webrtc/system_wrappers/source/aligned_array_unittest.cc60
-rw-r--r--webrtc/system_wrappers/source/aligned_malloc.cc100
-rw-r--r--webrtc/system_wrappers/source/aligned_malloc_unittest.cc82
-rw-r--r--webrtc/system_wrappers/source/android/cpu-features.c398
-rw-r--r--webrtc/system_wrappers/source/android/cpu-features.h56
-rw-r--r--webrtc/system_wrappers/source/atomic32_mac.cc49
-rw-r--r--webrtc/system_wrappers/source/atomic32_posix.cc53
-rw-r--r--webrtc/system_wrappers/source/atomic32_win.cc60
-rw-r--r--webrtc/system_wrappers/source/clock.cc271
-rw-r--r--webrtc/system_wrappers/source/clock_unittest.cc28
-rw-r--r--webrtc/system_wrappers/source/condition_variable.cc41
-rw-r--r--webrtc/system_wrappers/source/condition_variable_event_win.cc195
-rw-r--r--webrtc/system_wrappers/source/condition_variable_event_win.h46
-rw-r--r--webrtc/system_wrappers/source/condition_variable_native_win.cc104
-rw-r--r--webrtc/system_wrappers/source/condition_variable_native_win.h54
-rw-r--r--webrtc/system_wrappers/source/condition_variable_posix.cc132
-rw-r--r--webrtc/system_wrappers/source/condition_variable_posix.h42
-rw-r--r--webrtc/system_wrappers/source/condition_variable_unittest.cc205
-rw-r--r--webrtc/system_wrappers/source/cpu_features.cc72
-rw-r--r--webrtc/system_wrappers/source/cpu_features_android.c15
-rw-r--r--webrtc/system_wrappers/source/cpu_info.cc21
-rw-r--r--webrtc/system_wrappers/source/critical_section.cc28
-rw-r--r--webrtc/system_wrappers/source/critical_section_posix.cc41
-rw-r--r--webrtc/system_wrappers/source/critical_section_posix.h36
-rw-r--r--webrtc/system_wrappers/source/critical_section_unittest.cc137
-rw-r--r--webrtc/system_wrappers/source/critical_section_win.cc33
-rw-r--r--webrtc/system_wrappers/source/critical_section_win.h38
-rw-r--r--webrtc/system_wrappers/source/data_log.cc444
-rw-r--r--webrtc/system_wrappers/source/data_log_c.cc143
-rw-r--r--webrtc/system_wrappers/source/data_log_c_helpers_unittest.c124
-rw-r--r--webrtc/system_wrappers/source/data_log_c_helpers_unittest.h58
-rw-r--r--webrtc/system_wrappers/source/data_log_helpers_unittest.cc65
-rw-r--r--webrtc/system_wrappers/source/data_log_no_op.cc88
-rw-r--r--webrtc/system_wrappers/source/data_log_unittest.cc311
-rw-r--r--webrtc/system_wrappers/source/data_log_unittest_disabled.cc55
-rw-r--r--webrtc/system_wrappers/source/event.cc54
-rw-r--r--webrtc/system_wrappers/source/event_timer_posix.cc231
-rw-r--r--webrtc/system_wrappers/source/event_timer_posix.h60
-rw-r--r--webrtc/system_wrappers/source/event_timer_win.cc78
-rw-r--r--webrtc/system_wrappers/source/event_timer_win.h40
-rw-r--r--webrtc/system_wrappers/source/event_tracer.cc12
-rw-r--r--webrtc/system_wrappers/source/event_tracer_unittest.cc12
-rw-r--r--webrtc/system_wrappers/source/field_trial_default.cc62
-rw-r--r--webrtc/system_wrappers/source/file_impl.cc278
-rw-r--r--webrtc/system_wrappers/source/file_impl.h69
-rw-r--r--webrtc/system_wrappers/source/logcat_trace_context.cc63
-rw-r--r--webrtc/system_wrappers/source/logging.cc62
-rw-r--r--webrtc/system_wrappers/source/logging_unittest.cc89
-rw-r--r--webrtc/system_wrappers/source/metrics_default.cc29
-rw-r--r--webrtc/system_wrappers/source/rtp_to_ntp.cc150
-rw-r--r--webrtc/system_wrappers/source/rtp_to_ntp_unittest.cc146
-rw-r--r--webrtc/system_wrappers/source/rw_lock.cc37
-rw-r--r--webrtc/system_wrappers/source/rw_lock_generic.cc77
-rw-r--r--webrtc/system_wrappers/source/rw_lock_generic.h46
-rw-r--r--webrtc/system_wrappers/source/rw_lock_posix.cc51
-rw-r--r--webrtc/system_wrappers/source/rw_lock_posix.h41
-rw-r--r--webrtc/system_wrappers/source/rw_lock_win.cc97
-rw-r--r--webrtc/system_wrappers/source/rw_lock_win.h40
-rw-r--r--webrtc/system_wrappers/source/scoped_vector_unittest.cc328
-rw-r--r--webrtc/system_wrappers/source/sleep.cc36
-rw-r--r--webrtc/system_wrappers/source/sort.cc487
-rw-r--r--webrtc/system_wrappers/source/spreadsortlib/constants.hpp42
-rw-r--r--webrtc/system_wrappers/source/spreadsortlib/spreadsort.hpp1693
-rw-r--r--webrtc/system_wrappers/source/stl_util_unittest.cc250
-rw-r--r--webrtc/system_wrappers/source/stringize_macros_unittest.cc35
-rw-r--r--webrtc/system_wrappers/source/thread.cc33
-rw-r--r--webrtc/system_wrappers/source/thread_posix.cc166
-rw-r--r--webrtc/system_wrappers/source/thread_posix.h53
-rw-r--r--webrtc/system_wrappers/source/thread_posix_unittest.cc30
-rw-r--r--webrtc/system_wrappers/source/thread_unittest.cc53
-rw-r--r--webrtc/system_wrappers/source/thread_win.cc107
-rw-r--r--webrtc/system_wrappers/source/thread_win.h48
-rw-r--r--webrtc/system_wrappers/source/tick_util.cc98
-rw-r--r--webrtc/system_wrappers/source/timestamp_extrapolator.cc234
-rw-r--r--webrtc/system_wrappers/source/trace_impl.cc604
-rw-r--r--webrtc/system_wrappers/source/trace_impl.h106
-rw-r--r--webrtc/system_wrappers/source/trace_posix.cc90
-rw-r--r--webrtc/system_wrappers/source/trace_posix.h39
-rw-r--r--webrtc/system_wrappers/source/trace_win.cc97
-rw-r--r--webrtc/system_wrappers/source/trace_win.h36
82 files changed, 10245 insertions, 0 deletions
diff --git a/webrtc/system_wrappers/source/Android.mk b/webrtc/system_wrappers/source/Android.mk
new file mode 100644
index 0000000000..b58f902009
--- /dev/null
+++ b/webrtc/system_wrappers/source/Android.mk
@@ -0,0 +1,65 @@
+# Copyright (c) 2012 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(LOCAL_PATH)/../../../android-webrtc.mk
+
+LOCAL_ARM_MODE := arm
+LOCAL_MODULE := libwebrtc_system_wrappers
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+ android/cpu-features.c \
+ cpu_features_android.c \
+ sort.cc \
+ aligned_malloc.cc \
+ atomic32_posix.cc \
+ condition_variable.cc \
+ cpu_features.cc \
+ cpu_info.cc \
+ critical_section.cc \
+ event.cc \
+ file_impl.cc \
+ logging.cc \
+ metrics_default.cc \
+ rw_lock.cc \
+ thread.cc \
+ trace_impl.cc \
+ condition_variable_posix.cc \
+ critical_section_posix.cc \
+ sleep.cc \
+ thread_posix.cc \
+ trace_posix.cc \
+ rw_lock_posix.cc \
+
+LOCAL_CFLAGS := $(MY_WEBRTC_COMMON_DEFS)
+LOCAL_CPPFLAGS := -std=c++0x
+
+LOCAL_CFLAGS_arm := $(MY_WEBRTC_COMMON_DEFS_arm)
+LOCAL_CFLAGS_x86 := $(MY_WEBRTC_COMMON_DEFS_x86)
+LOCAL_CFLAGS_mips := $(MY_WEBRTC_COMMON_DEFS_mips)
+LOCAL_CFLAGS_arm64 := $(MY_WEBRTC_COMMON_DEFS_arm64)
+LOCAL_CFLAGS_x86_64 := $(MY_WEBRTC_COMMON_DEFS_x86_64)
+LOCAL_CFLAGS_mips64 := $(MY_WEBRTC_COMMON_DEFS_mips64)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/android \
+ $(LOCAL_PATH)/../../.. \
+ $(LOCAL_PATH)/../interface \
+ $(LOCAL_PATH)/spreadsortlib
+
+ifdef WEBRTC_STL
+LOCAL_NDK_STL_VARIANT := $(WEBRTC_STL)
+LOCAL_SDK_VERSION := 14
+LOCAL_MODULE := $(LOCAL_MODULE)_$(WEBRTC_STL)
+endif
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc/system_wrappers/source/OWNERS b/webrtc/system_wrappers/source/OWNERS
new file mode 100644
index 0000000000..bbffda7e49
--- /dev/null
+++ b/webrtc/system_wrappers/source/OWNERS
@@ -0,0 +1,6 @@
+per-file *.isolate=kjellander@webrtc.org
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file *.gyp=*
+per-file *.gypi=*
diff --git a/webrtc/system_wrappers/source/aligned_array_unittest.cc b/webrtc/system_wrappers/source/aligned_array_unittest.cc
new file mode 100644
index 0000000000..8d898af03e
--- /dev/null
+++ b/webrtc/system_wrappers/source/aligned_array_unittest.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 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 "webrtc/system_wrappers/include/aligned_array.h"
+
+#include <stdint.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+bool IsAligned(const void* ptr, int alignment) {
+ return reinterpret_cast<uintptr_t>(ptr) % alignment == 0;
+}
+
+} // namespace
+
+namespace webrtc {
+
+TEST(AlignedArrayTest, CheckAlignment) {
+ AlignedArray<bool> arr(10, 7, 128);
+ ASSERT_TRUE(IsAligned(arr.Array(), 128));
+ for (int i = 0; i < 10; ++i) {
+ ASSERT_TRUE(IsAligned(arr.Row(i), 128));
+ ASSERT_EQ(arr.Row(i), arr.Array()[i]);
+ }
+}
+
+TEST(AlignedArrayTest, CheckOverlap) {
+ AlignedArray<size_t> arr(10, 7, 128);
+
+ for (int i = 0; i < 10; ++i) {
+ for (size_t j = 0; j < 7; ++j) {
+ arr.At(i, j) = 20 * i + j;
+ }
+ }
+
+ for (int i = 0; i < 10; ++i) {
+ for (size_t j = 0; j < 7; ++j) {
+ ASSERT_EQ(arr.At(i, j), 20 * i + j);
+ ASSERT_EQ(arr.Row(i)[j], 20 * i + j);
+ ASSERT_EQ(arr.Array()[i][j], 20 * i + j);
+ }
+ }
+}
+
+TEST(AlignedArrayTest, CheckRowsCols) {
+ AlignedArray<bool> arr(10, 7, 128);
+ ASSERT_EQ(arr.rows(), 10);
+ ASSERT_EQ(arr.cols(), 7u);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/aligned_malloc.cc b/webrtc/system_wrappers/source/aligned_malloc.cc
new file mode 100644
index 0000000000..a654e97e75
--- /dev/null
+++ b/webrtc/system_wrappers/source/aligned_malloc.cc
@@ -0,0 +1,100 @@
+/*
+ * 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 "webrtc/system_wrappers/include/aligned_malloc.h"
+
+#include <memory.h>
+#include <stdlib.h>
+
+#if _WIN32
+#include <windows.h>
+#else
+#include <stdint.h>
+#endif
+
+#include "webrtc/typedefs.h"
+
+// Reference on memory alignment:
+// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
+namespace webrtc {
+
+uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
+ // The pointer should be aligned with |alignment| bytes. The - 1 guarantees
+ // that it is aligned towards the closest higher (right) address.
+ return (start_pos + alignment - 1) & ~(alignment - 1);
+}
+
+// Alignment must be an integer power of two.
+bool ValidAlignment(size_t alignment) {
+ if (!alignment) {
+ return false;
+ }
+ return (alignment & (alignment - 1)) == 0;
+}
+
+void* GetRightAlign(const void* pointer, size_t alignment) {
+ if (!pointer) {
+ return NULL;
+ }
+ if (!ValidAlignment(alignment)) {
+ return NULL;
+ }
+ uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
+ return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
+}
+
+void* AlignedMalloc(size_t size, size_t alignment) {
+ if (size == 0) {
+ return NULL;
+ }
+ if (!ValidAlignment(alignment)) {
+ return NULL;
+ }
+
+ // The memory is aligned towards the lowest address that so only
+ // alignment - 1 bytes needs to be allocated.
+ // A pointer to the start of the memory must be stored so that it can be
+ // retreived for deletion, ergo the sizeof(uintptr_t).
+ void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
+ if (memory_pointer == NULL) {
+ return NULL;
+ }
+
+ // Aligning after the sizeof(uintptr_t) bytes will leave room for the header
+ // in the same memory block.
+ uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
+ align_start_pos += sizeof(uintptr_t);
+ uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
+ void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
+
+ // Store the address to the beginning of the memory just before the aligned
+ // memory.
+ uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
+ void* header_pointer = reinterpret_cast<void*>(header_pos);
+ uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
+ memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
+
+ return aligned_pointer;
+}
+
+void AlignedFree(void* mem_block) {
+ if (mem_block == NULL) {
+ return;
+ }
+ uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
+ uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
+
+ // Read out the address of the AlignedMemory struct from the header.
+ uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
+ void* memory_start = reinterpret_cast<void*>(memory_start_pos);
+ free(memory_start);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/aligned_malloc_unittest.cc b/webrtc/system_wrappers/source/aligned_malloc_unittest.cc
new file mode 100644
index 0000000000..3933c2ac05
--- /dev/null
+++ b/webrtc/system_wrappers/source/aligned_malloc_unittest.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/aligned_malloc.h"
+
+#if _WIN32
+#include <windows.h>
+#else
+#include <stdint.h>
+#endif
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+// Returns true if |size| and |alignment| are valid combinations.
+bool CorrectUsage(size_t size, size_t alignment) {
+ rtc::scoped_ptr<char, AlignedFreeDeleter> scoped(
+ static_cast<char*>(AlignedMalloc(size, alignment)));
+ if (scoped.get() == NULL) {
+ return false;
+ }
+ const uintptr_t scoped_address = reinterpret_cast<uintptr_t> (scoped.get());
+ return 0u == scoped_address % alignment;
+}
+
+TEST(AlignedMalloc, GetRightAlign) {
+ const size_t size = 100;
+ const size_t alignment = 32;
+ const size_t left_misalignment = 1;
+ rtc::scoped_ptr<char, AlignedFreeDeleter> scoped(
+ static_cast<char*>(AlignedMalloc(size, alignment)));
+ EXPECT_TRUE(scoped.get() != NULL);
+ const uintptr_t aligned_address = reinterpret_cast<uintptr_t> (scoped.get());
+ const uintptr_t misaligned_address = aligned_address - left_misalignment;
+ const char* misaligned_ptr = reinterpret_cast<const char*>(
+ misaligned_address);
+ const char* realigned_ptr = GetRightAlign(misaligned_ptr, alignment);
+ EXPECT_EQ(scoped.get(), realigned_ptr);
+}
+
+TEST(AlignedMalloc, IncorrectSize) {
+ const size_t incorrect_size = 0;
+ const size_t alignment = 64;
+ EXPECT_FALSE(CorrectUsage(incorrect_size, alignment));
+}
+
+TEST(AlignedMalloc, IncorrectAlignment) {
+ const size_t size = 100;
+ const size_t incorrect_alignment = 63;
+ EXPECT_FALSE(CorrectUsage(size, incorrect_alignment));
+}
+
+TEST(AlignedMalloc, AlignTo2Bytes) {
+ size_t size = 100;
+ size_t alignment = 2;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+TEST(AlignedMalloc, AlignTo32Bytes) {
+ size_t size = 100;
+ size_t alignment = 32;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+TEST(AlignedMalloc, AlignTo128Bytes) {
+ size_t size = 100;
+ size_t alignment = 128;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+} // namespace webrtc
+
diff --git a/webrtc/system_wrappers/source/android/cpu-features.c b/webrtc/system_wrappers/source/android/cpu-features.c
new file mode 100644
index 0000000000..749e7b3781
--- /dev/null
+++ b/webrtc/system_wrappers/source/android/cpu-features.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2012 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 <sys/system_properties.h>
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+#include <pthread.h>
+#include "cpu-features.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static pthread_once_t g_once;
+static AndroidCpuFamily g_cpuFamily;
+static uint64_t g_cpuFeatures;
+static int g_cpuCount;
+
+static const int android_cpufeatures_debug = 0;
+
+#ifdef __arm__
+# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM
+#elif defined __i386__
+# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86
+#else
+# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN
+#endif
+
+#define D(...) \
+ do { \
+ if (android_cpufeatures_debug) { \
+ printf(__VA_ARGS__); fflush(stdout); \
+ } \
+ } while (0)
+
+#ifdef __i386__
+static __inline__ void x86_cpuid(int func, int values[4])
+{
+ int a, b, c, d;
+ /* We need to preserve ebx since we're compiling PIC code */
+ /* this means we can't use "=b" for the second output register */
+ __asm__ __volatile__ ( \
+ "push %%ebx\n"
+ "cpuid\n" \
+ "mov %1, %%ebx\n"
+ "pop %%ebx\n"
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "a" (func) \
+ );
+ values[0] = a;
+ values[1] = b;
+ values[2] = c;
+ values[3] = d;
+}
+#endif
+
+/* Read the content of /proc/cpuinfo into a user-provided buffer.
+ * Return the length of the data, or -1 on error. Does *not*
+ * zero-terminate the content. Will not read more
+ * than 'buffsize' bytes.
+ */
+static int
+read_file(const char* pathname, char* buffer, size_t buffsize)
+{
+ int fd, len;
+
+ fd = open(pathname, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ do {
+ len = read(fd, buffer, buffsize);
+ } while (len < 0 && errno == EINTR);
+
+ close(fd);
+
+ return len;
+}
+
+/* Extract the content of a the first occurence of a given field in
+ * the content of /proc/cpuinfo and return it as a heap-allocated
+ * string that must be freed by the caller.
+ *
+ * Return NULL if not found
+ */
+static char*
+extract_cpuinfo_field(char* buffer, int buflen, const char* field)
+{
+ int fieldlen = strlen(field);
+ char* bufend = buffer + buflen;
+ char* result = NULL;
+ int len, ignore;
+ const char *p, *q;
+
+ /* Look for first field occurence, and ensures it starts the line.
+ */
+ p = buffer;
+ bufend = buffer + buflen;
+ for (;;) {
+ p = memmem(p, bufend-p, field, fieldlen);
+ if (p == NULL)
+ goto EXIT;
+
+ if (p == buffer || p[-1] == '\n')
+ break;
+
+ p += fieldlen;
+ }
+
+ /* Skip to the first column followed by a space */
+ p += fieldlen;
+ p = memchr(p, ':', bufend-p);
+ if (p == NULL || p[1] != ' ')
+ goto EXIT;
+
+ /* Find the end of the line */
+ p += 2;
+ q = memchr(p, '\n', bufend-p);
+ if (q == NULL)
+ q = bufend;
+
+ /* Copy the line into a heap-allocated buffer */
+ len = q-p;
+ result = malloc(len+1);
+ if (result == NULL)
+ goto EXIT;
+
+ memcpy(result, p, len);
+ result[len] = '\0';
+
+EXIT:
+ return result;
+}
+
+/* Count the number of occurences of a given field prefix in /proc/cpuinfo.
+ */
+static int
+count_cpuinfo_field(char* buffer, int buflen, const char* field)
+{
+ int fieldlen = strlen(field);
+ const char* p = buffer;
+ const char* bufend = buffer + buflen;
+ const char* q;
+ int count = 0;
+
+ for (;;) {
+ const char* q;
+
+ p = memmem(p, bufend-p, field, fieldlen);
+ if (p == NULL)
+ break;
+
+ /* Ensure that the field is at the start of a line */
+ if (p > buffer && p[-1] != '\n') {
+ p += fieldlen;
+ continue;
+ }
+
+
+ /* skip any whitespace */
+ q = p + fieldlen;
+ while (q < bufend && (*q == ' ' || *q == '\t'))
+ q++;
+
+ /* we must have a colon now */
+ if (q < bufend && *q == ':') {
+ count += 1;
+ q ++;
+ }
+ p = q;
+ }
+
+ return count;
+}
+
+/* Like strlen(), but for constant string literals */
+#define STRLEN_CONST(x) ((sizeof(x)-1)
+
+
+/* Checks that a space-separated list of items contains one given 'item'.
+ * Returns 1 if found, 0 otherwise.
+ */
+static int
+has_list_item(const char* list, const char* item)
+{
+ const char* p = list;
+ int itemlen = strlen(item);
+
+ if (list == NULL)
+ return 0;
+
+ while (*p) {
+ const char* q;
+
+ /* skip spaces */
+ while (*p == ' ' || *p == '\t')
+ p++;
+
+ /* find end of current list item */
+ q = p;
+ while (*q && *q != ' ' && *q != '\t')
+ q++;
+
+ if (itemlen == q-p && !memcmp(p, item, itemlen))
+ return 1;
+
+ /* skip to next item */
+ p = q;
+ }
+ return 0;
+}
+
+
+static void
+android_cpuInit(void)
+{
+ char cpuinfo[4096];
+ int cpuinfo_len;
+
+ g_cpuFamily = DEFAULT_CPU_FAMILY;
+ g_cpuFeatures = 0;
+ g_cpuCount = 1;
+
+ cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo);
+ D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len,
+ cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo);
+
+ if (cpuinfo_len < 0) /* should not happen */ {
+ return;
+ }
+
+ /* Count the CPU cores, the value may be 0 for single-core CPUs */
+ g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "processor");
+ if (g_cpuCount == 0) {
+ g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "Processor");
+ if (g_cpuCount == 0) {
+ g_cpuCount = 1;
+ }
+ }
+
+ D("found cpuCount = %d\n", g_cpuCount);
+
+#ifdef __ARM_ARCH__
+ {
+ char* features = NULL;
+ char* architecture = NULL;
+
+ /* Extract architecture from the "CPU Architecture" field.
+ * The list is well-known, unlike the the output of
+ * the 'Processor' field which can vary greatly.
+ *
+ * See the definition of the 'proc_arch' array in
+ * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
+ * same file.
+ */
+ char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture");
+
+ if (cpuArch != NULL) {
+ char* end;
+ long archNumber;
+ int hasARMv7 = 0;
+
+ D("found cpuArch = '%s'\n", cpuArch);
+
+ /* read the initial decimal number, ignore the rest */
+ archNumber = strtol(cpuArch, &end, 10);
+
+ /* Here we assume that ARMv8 will be upwards compatible with v7
+ * in the future. Unfortunately, there is no 'Features' field to
+ * indicate that Thumb-2 is supported.
+ */
+ if (end > cpuArch && archNumber >= 7) {
+ hasARMv7 = 1;
+ }
+
+ /* Unfortunately, it seems that certain ARMv6-based CPUs
+ * report an incorrect architecture number of 7!
+ *
+ * See http://code.google.com/p/android/issues/detail?id=10812
+ *
+ * We try to correct this by looking at the 'elf_format'
+ * field reported by the 'Processor' field, which is of the
+ * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
+ * an ARMv6-one.
+ */
+ if (hasARMv7) {
+ char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
+ "Processor");
+ if (cpuProc != NULL) {
+ D("found cpuProc = '%s'\n", cpuProc);
+ if (has_list_item(cpuProc, "(v6l)")) {
+ D("CPU processor and architecture mismatch!!\n");
+ hasARMv7 = 0;
+ }
+ free(cpuProc);
+ }
+ }
+
+ if (hasARMv7) {
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
+ }
+
+ /* The LDREX / STREX instructions are available from ARMv6 */
+ if (archNumber >= 6) {
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
+ }
+
+ free(cpuArch);
+ }
+
+ /* Extract the list of CPU features from 'Features' field */
+ char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features");
+
+ if (cpuFeatures != NULL) {
+
+ D("found cpuFeatures = '%s'\n", cpuFeatures);
+
+ if (has_list_item(cpuFeatures, "vfpv3"))
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
+
+ else if (has_list_item(cpuFeatures, "vfpv3d16"))
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
+
+ if (has_list_item(cpuFeatures, "neon")) {
+ /* Note: Certain kernels only report neon but not vfpv3
+ * in their features list. However, ARM mandates
+ * that if Neon is implemented, so must be VFPv3
+ * so always set the flag.
+ */
+ g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON |
+ ANDROID_CPU_ARM_FEATURE_VFPv3;
+ }
+ free(cpuFeatures);
+ }
+ }
+#endif /* __ARM_ARCH__ */
+
+#ifdef __i386__
+ g_cpuFamily = ANDROID_CPU_FAMILY_X86;
+
+ int regs[4];
+
+/* According to http://en.wikipedia.org/wiki/CPUID */
+#define VENDOR_INTEL_b 0x756e6547
+#define VENDOR_INTEL_c 0x6c65746e
+#define VENDOR_INTEL_d 0x49656e69
+
+ x86_cpuid(0, regs);
+ int vendorIsIntel = (regs[1] == VENDOR_INTEL_b &&
+ regs[2] == VENDOR_INTEL_c &&
+ regs[3] == VENDOR_INTEL_d);
+
+ x86_cpuid(1, regs);
+ if ((regs[2] & (1 << 9)) != 0) {
+ g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
+ }
+ if ((regs[2] & (1 << 23)) != 0) {
+ g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
+ }
+ if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) {
+ g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
+ }
+#endif
+}
+
+
+AndroidCpuFamily
+android_getCpuFamily(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuFamily;
+}
+
+
+uint64_t
+android_getCpuFeatures(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuFeatures;
+}
+
+
+int
+android_getCpuCount(void)
+{
+ pthread_once(&g_once, android_cpuInit);
+ return g_cpuCount;
+}
diff --git a/webrtc/system_wrappers/source/android/cpu-features.h b/webrtc/system_wrappers/source/android/cpu-features.h
new file mode 100644
index 0000000000..f20c0bc4d9
--- /dev/null
+++ b/webrtc/system_wrappers/source/android/cpu-features.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+// You can download Android source at
+// http://source.android.com/source/downloading.html
+// Original files are in ndk/sources/android/cpufeatures
+// Revision is Change-Id: I9a0629efba36a6023f05e5f092e7addcc1b7d2a9
+
+#ifndef CPU_FEATURES_H
+#define CPU_FEATURES_H
+
+#include <sys/cdefs.h>
+#include <stdint.h>
+
+__BEGIN_DECLS
+
+typedef enum {
+ ANDROID_CPU_FAMILY_UNKNOWN = 0,
+ ANDROID_CPU_FAMILY_ARM,
+ ANDROID_CPU_FAMILY_X86,
+
+ ANDROID_CPU_FAMILY_MAX /* do not remove */
+
+} AndroidCpuFamily;
+
+/* Return family of the device's CPU */
+extern AndroidCpuFamily android_getCpuFamily(void);
+
+enum {
+ ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0),
+ ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1),
+ ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2),
+ ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3),
+};
+
+enum {
+ ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0),
+ ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1),
+ ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2),
+};
+
+extern uint64_t android_getCpuFeatures(void);
+
+/* Return the number of CPU cores detected on this device. */
+extern int android_getCpuCount(void);
+
+__END_DECLS
+
+#endif /* CPU_FEATURES_H */
diff --git a/webrtc/system_wrappers/source/atomic32_mac.cc b/webrtc/system_wrappers/source/atomic32_mac.cc
new file mode 100644
index 0000000000..7c77d092b5
--- /dev/null
+++ b/webrtc/system_wrappers/source/atomic32_mac.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/atomic32.h"
+
+#include <assert.h>
+#include <libkern/OSAtomic.h>
+#include <stdlib.h>
+
+#include "webrtc/common_types.h"
+
+namespace webrtc {
+
+Atomic32::Atomic32(int32_t initial_value)
+ : value_(initial_value) {
+ assert(Is32bitAligned());
+}
+
+Atomic32::~Atomic32() {
+}
+
+int32_t Atomic32::operator++() {
+ return OSAtomicIncrement32Barrier(&value_);
+}
+
+int32_t Atomic32::operator--() {
+ return OSAtomicDecrement32Barrier(&value_);
+}
+
+int32_t Atomic32::operator+=(int32_t value) {
+ return OSAtomicAdd32Barrier(value, &value_);
+}
+
+int32_t Atomic32::operator-=(int32_t value) {
+ return OSAtomicAdd32Barrier(-value, &value_);
+}
+
+bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
+ return OSAtomicCompareAndSwap32Barrier(compare_value, new_value, &value_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/atomic32_posix.cc b/webrtc/system_wrappers/source/atomic32_posix.cc
new file mode 100644
index 0000000000..fbc9c2910e
--- /dev/null
+++ b/webrtc/system_wrappers/source/atomic32_posix.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/atomic32.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <malloc.h>
+
+#include "webrtc/common_types.h"
+
+namespace webrtc {
+
+Atomic32::Atomic32(int32_t initial_value)
+ : value_(initial_value) {
+ assert(Is32bitAligned());
+}
+
+Atomic32::~Atomic32() {
+}
+
+int32_t Atomic32::operator++() {
+ return __sync_fetch_and_add(&value_, 1) + 1;
+}
+
+int32_t Atomic32::operator--() {
+ return __sync_fetch_and_sub(&value_, 1) - 1;
+}
+
+int32_t Atomic32::operator+=(int32_t value) {
+ int32_t return_value = __sync_fetch_and_add(&value_, value);
+ return_value += value;
+ return return_value;
+}
+
+int32_t Atomic32::operator-=(int32_t value) {
+ int32_t return_value = __sync_fetch_and_sub(&value_, value);
+ return_value -= value;
+ return return_value;
+}
+
+bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
+ return __sync_bool_compare_and_swap(&value_, compare_value, new_value);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/atomic32_win.cc b/webrtc/system_wrappers/source/atomic32_win.cc
new file mode 100644
index 0000000000..cd4ce08580
--- /dev/null
+++ b/webrtc/system_wrappers/source/atomic32_win.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/atomic32.h"
+
+#include <assert.h>
+#include <windows.h>
+
+#include "webrtc/common_types.h"
+
+namespace webrtc {
+
+Atomic32::Atomic32(int32_t initial_value)
+ : value_(initial_value) {
+ static_assert(sizeof(value_) == sizeof(LONG),
+ "counter variable is the expected size");
+ assert(Is32bitAligned());
+}
+
+Atomic32::~Atomic32() {
+}
+
+int32_t Atomic32::operator++() {
+ return static_cast<int32_t>(InterlockedIncrement(
+ reinterpret_cast<volatile LONG*>(&value_)));
+}
+
+int32_t Atomic32::operator--() {
+ return static_cast<int32_t>(InterlockedDecrement(
+ reinterpret_cast<volatile LONG*>(&value_)));
+}
+
+int32_t Atomic32::operator+=(int32_t value) {
+ return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&value_),
+ value);
+}
+
+int32_t Atomic32::operator-=(int32_t value) {
+ return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&value_),
+ -value);
+}
+
+bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
+ const LONG old_value = InterlockedCompareExchange(
+ reinterpret_cast<volatile LONG*>(&value_),
+ new_value,
+ compare_value);
+
+ // If the old value and the compare value is the same an exchange happened.
+ return (old_value == compare_value);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/clock.cc b/webrtc/system_wrappers/source/clock.cc
new file mode 100644
index 0000000000..95df256f3c
--- /dev/null
+++ b/webrtc/system_wrappers/source/clock.cc
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2013 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 "webrtc/system_wrappers/include/clock.h"
+
+#if defined(_WIN32)
+// Windows needs to be included before mmsystem.h
+#include "webrtc/base/win32.h"
+#include <MMSystem.h>
+#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include "webrtc/base/criticalsection.h"
+#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+#include "webrtc/system_wrappers/include/tick_util.h"
+
+namespace webrtc {
+
+const double kNtpFracPerMs = 4.294967296E6;
+
+int64_t Clock::NtpToMs(uint32_t ntp_secs, uint32_t ntp_frac) {
+ const double ntp_frac_ms = static_cast<double>(ntp_frac) / kNtpFracPerMs;
+ return 1000 * static_cast<int64_t>(ntp_secs) +
+ static_cast<int64_t>(ntp_frac_ms + 0.5);
+}
+
+class RealTimeClock : public Clock {
+ // Return a timestamp in milliseconds relative to some arbitrary source; the
+ // source is fixed for this clock.
+ int64_t TimeInMilliseconds() const override {
+ return TickTime::MillisecondTimestamp();
+ }
+
+ // Return a timestamp in microseconds relative to some arbitrary source; the
+ // source is fixed for this clock.
+ int64_t TimeInMicroseconds() const override {
+ return TickTime::MicrosecondTimestamp();
+ }
+
+ // Retrieve an NTP absolute timestamp in seconds and fractions of a second.
+ void CurrentNtp(uint32_t& seconds, uint32_t& fractions) const override {
+ timeval tv = CurrentTimeVal();
+ double microseconds_in_seconds;
+ Adjust(tv, &seconds, &microseconds_in_seconds);
+ fractions = static_cast<uint32_t>(
+ microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);
+ }
+
+ // Retrieve an NTP absolute timestamp in milliseconds.
+ int64_t CurrentNtpInMilliseconds() const override {
+ timeval tv = CurrentTimeVal();
+ uint32_t seconds;
+ double microseconds_in_seconds;
+ Adjust(tv, &seconds, &microseconds_in_seconds);
+ return 1000 * static_cast<int64_t>(seconds) +
+ static_cast<int64_t>(1000.0 * microseconds_in_seconds + 0.5);
+ }
+
+ protected:
+ virtual timeval CurrentTimeVal() const = 0;
+
+ static void Adjust(const timeval& tv, uint32_t* adjusted_s,
+ double* adjusted_us_in_s) {
+ *adjusted_s = tv.tv_sec + kNtpJan1970;
+ *adjusted_us_in_s = tv.tv_usec / 1e6;
+
+ if (*adjusted_us_in_s >= 1) {
+ *adjusted_us_in_s -= 1;
+ ++*adjusted_s;
+ } else if (*adjusted_us_in_s < -1) {
+ *adjusted_us_in_s += 1;
+ --*adjusted_s;
+ }
+ }
+};
+
+#if defined(_WIN32)
+// TODO(pbos): Consider modifying the implementation to synchronize itself
+// against system time (update ref_point_, make it non-const) periodically to
+// prevent clock drift.
+class WindowsRealTimeClock : public RealTimeClock {
+ public:
+ WindowsRealTimeClock()
+ : last_time_ms_(0),
+ num_timer_wraps_(0),
+ ref_point_(GetSystemReferencePoint()) {}
+
+ virtual ~WindowsRealTimeClock() {}
+
+ protected:
+ struct ReferencePoint {
+ FILETIME file_time;
+ LARGE_INTEGER counter_ms;
+ };
+
+ timeval CurrentTimeVal() const override {
+ const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
+
+ FILETIME StartTime;
+ uint64_t Time;
+ struct timeval tv;
+
+ // We can't use query performance counter since they can change depending on
+ // speed stepping.
+ GetTime(&StartTime);
+
+ Time = (((uint64_t) StartTime.dwHighDateTime) << 32) +
+ (uint64_t) StartTime.dwLowDateTime;
+
+ // Convert the hecto-nano second time to tv format.
+ Time -= FILETIME_1970;
+
+ tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
+ tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
+ return tv;
+ }
+
+ void GetTime(FILETIME* current_time) const {
+ DWORD t;
+ LARGE_INTEGER elapsed_ms;
+ {
+ rtc::CritScope lock(&crit_);
+ // time MUST be fetched inside the critical section to avoid non-monotonic
+ // last_time_ms_ values that'll register as incorrect wraparounds due to
+ // concurrent calls to GetTime.
+ t = timeGetTime();
+ if (t < last_time_ms_)
+ num_timer_wraps_++;
+ last_time_ms_ = t;
+ elapsed_ms.HighPart = num_timer_wraps_;
+ }
+ elapsed_ms.LowPart = t;
+ elapsed_ms.QuadPart = elapsed_ms.QuadPart - ref_point_.counter_ms.QuadPart;
+
+ // Translate to 100-nanoseconds intervals (FILETIME resolution)
+ // and add to reference FILETIME to get current FILETIME.
+ ULARGE_INTEGER filetime_ref_as_ul;
+ filetime_ref_as_ul.HighPart = ref_point_.file_time.dwHighDateTime;
+ filetime_ref_as_ul.LowPart = ref_point_.file_time.dwLowDateTime;
+ filetime_ref_as_ul.QuadPart +=
+ static_cast<ULONGLONG>((elapsed_ms.QuadPart) * 1000 * 10);
+
+ // Copy to result
+ current_time->dwHighDateTime = filetime_ref_as_ul.HighPart;
+ current_time->dwLowDateTime = filetime_ref_as_ul.LowPart;
+ }
+
+ static ReferencePoint GetSystemReferencePoint() {
+ ReferencePoint ref = {};
+ FILETIME ft0 = {};
+ FILETIME ft1 = {};
+ // Spin waiting for a change in system time. As soon as this change happens,
+ // get the matching call for timeGetTime() as soon as possible. This is
+ // assumed to be the most accurate offset that we can get between
+ // timeGetTime() and system time.
+
+ // Set timer accuracy to 1 ms.
+ timeBeginPeriod(1);
+ GetSystemTimeAsFileTime(&ft0);
+ do {
+ GetSystemTimeAsFileTime(&ft1);
+
+ ref.counter_ms.QuadPart = timeGetTime();
+ Sleep(0);
+ } while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
+ (ft0.dwLowDateTime == ft1.dwLowDateTime));
+ ref.file_time = ft1;
+ timeEndPeriod(1);
+ return ref;
+ }
+
+ // mutable as time-accessing functions are const.
+ mutable rtc::CriticalSection crit_;
+ mutable DWORD last_time_ms_;
+ mutable LONG num_timer_wraps_;
+ const ReferencePoint ref_point_;
+};
+
+#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
+class UnixRealTimeClock : public RealTimeClock {
+ public:
+ UnixRealTimeClock() {}
+
+ ~UnixRealTimeClock() override {}
+
+ protected:
+ timeval CurrentTimeVal() const override {
+ struct timeval tv;
+ struct timezone tz;
+ tz.tz_minuteswest = 0;
+ tz.tz_dsttime = 0;
+ gettimeofday(&tv, &tz);
+ return tv;
+ }
+};
+#endif
+
+#if defined(_WIN32)
+static WindowsRealTimeClock* volatile g_shared_clock = nullptr;
+#endif
+Clock* Clock::GetRealTimeClock() {
+#if defined(_WIN32)
+ // This read relies on volatile read being atomic-load-acquire. This is
+ // true in MSVC since at least 2005:
+ // "A read of a volatile object (volatile read) has Acquire semantics"
+ if (g_shared_clock != nullptr)
+ return g_shared_clock;
+ WindowsRealTimeClock* clock = new WindowsRealTimeClock;
+ if (InterlockedCompareExchangePointer(
+ reinterpret_cast<void* volatile*>(&g_shared_clock), clock, nullptr) !=
+ nullptr) {
+ // g_shared_clock was assigned while we constructed/tried to assign our
+ // instance, delete our instance and use the existing one.
+ delete clock;
+ }
+ return g_shared_clock;
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+ static UnixRealTimeClock clock;
+ return &clock;
+#else
+ return NULL;
+#endif
+}
+
+SimulatedClock::SimulatedClock(int64_t initial_time_us)
+ : time_us_(initial_time_us), lock_(RWLockWrapper::CreateRWLock()) {
+}
+
+SimulatedClock::~SimulatedClock() {
+}
+
+int64_t SimulatedClock::TimeInMilliseconds() const {
+ ReadLockScoped synchronize(*lock_);
+ return (time_us_ + 500) / 1000;
+}
+
+int64_t SimulatedClock::TimeInMicroseconds() const {
+ ReadLockScoped synchronize(*lock_);
+ return time_us_;
+}
+
+void SimulatedClock::CurrentNtp(uint32_t& seconds, uint32_t& fractions) const {
+ int64_t now_ms = TimeInMilliseconds();
+ seconds = (now_ms / 1000) + kNtpJan1970;
+ fractions =
+ static_cast<uint32_t>((now_ms % 1000) * kMagicNtpFractionalUnit / 1000);
+}
+
+int64_t SimulatedClock::CurrentNtpInMilliseconds() const {
+ return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970);
+}
+
+void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
+ AdvanceTimeMicroseconds(1000 * milliseconds);
+}
+
+void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
+ WriteLockScoped synchronize(*lock_);
+ time_us_ += microseconds;
+}
+
+}; // namespace webrtc
diff --git a/webrtc/system_wrappers/source/clock_unittest.cc b/webrtc/system_wrappers/source/clock_unittest.cc
new file mode 100644
index 0000000000..9cb8ec73d0
--- /dev/null
+++ b/webrtc/system_wrappers/source/clock_unittest.cc
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/clock.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace webrtc {
+
+TEST(ClockTest, NtpTime) {
+ Clock* clock = Clock::GetRealTimeClock();
+ uint32_t seconds;
+ uint32_t fractions;
+ clock->CurrentNtp(seconds, fractions);
+ int64_t milliseconds = clock->CurrentNtpInMilliseconds();
+ EXPECT_GT(milliseconds / 1000, kNtpJan1970);
+ EXPECT_GE(milliseconds, Clock::NtpToMs(seconds, fractions));
+ EXPECT_NEAR(milliseconds, Clock::NtpToMs(seconds, fractions), 100);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable.cc b/webrtc/system_wrappers/source/condition_variable.cc
new file mode 100644
index 0000000000..f5ae93adc6
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable.cc
@@ -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.
+ */
+
+#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
+#include "webrtc/system_wrappers/source/condition_variable_native_win.h"
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+#include <pthread.h>
+#include "webrtc/system_wrappers/source/condition_variable_posix.h"
+#endif
+
+namespace webrtc {
+
+ConditionVariableWrapper* ConditionVariableWrapper::CreateConditionVariable() {
+#if defined(_WIN32)
+ // Try to create native condition variable implementation.
+ ConditionVariableWrapper* ret_val = ConditionVariableNativeWin::Create();
+ if (!ret_val) {
+ // Native condition variable implementation does not exist. Create generic
+ // condition variable based on events.
+ ret_val = new ConditionVariableEventWin();
+ }
+ return ret_val;
+#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
+ return ConditionVariablePosix::Create();
+#else
+ return NULL;
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable_event_win.cc b/webrtc/system_wrappers/source/condition_variable_event_win.cc
new file mode 100644
index 0000000000..41b019dad3
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable_event_win.cc
@@ -0,0 +1,195 @@
+/*
+Source:
+http://www1.cse.wustl.edu/~schmidt/ACE-copying.html
+
+License:
+Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM),
+and CoSMIC(TM)
+
+ACE(TM), TAO(TM), CIAO(TM), DAnCE>(TM), and CoSMIC(TM) (henceforth referred to
+as "DOC software") are copyrighted by Douglas C. Schmidt and his research
+group at Washington University, University of California, Irvine, and
+Vanderbilt University, Copyright (c) 1993-2009, all rights reserved. Since DOC
+software is open-source, freely available software, you are free to use,
+modify, copy, and distribute--perpetually and irrevocably--the DOC software
+source code and object code produced from the source, as well as copy and
+distribute modified versions of this software. You must, however, include this
+copyright statement along with any code built using DOC software that you
+release. No copyright statement needs to be provided if you just ship binary
+executables of your software products.
+You can use DOC software in commercial and/or binary software releases and are
+under no obligation to redistribute any of your source code that is built
+using DOC software. Note, however, that you may not misappropriate the DOC
+software code, such as copyrighting it yourself or claiming authorship of the
+DOC software code, in a way that will prevent DOC software from being
+distributed freely using an open-source development model. You needn't inform
+anyone that you're using DOC software in your software, though we encourage
+you to let us know so we can promote your project in the DOC software success
+stories.
+
+The ACE, TAO, CIAO, DAnCE, and CoSMIC web sites are maintained by the DOC
+Group at the Institute for Software Integrated Systems (ISIS) and the Center
+for Distributed Object Computing of Washington University, St. Louis for the
+development of open-source software as part of the open-source software
+community. Submissions are provided by the submitter ``as is'' with no
+warranties whatsoever, including any warranty of merchantability,
+noninfringement of third party intellectual property, or fitness for any
+particular purpose. In no event shall the submitter be liable for any direct,
+indirect, special, exemplary, punitive, or consequential damages, including
+without limitation, lost profits, even if advised of the possibility of such
+damages. Likewise, DOC software is provided as is with no warranties of any
+kind, including the warranties of design, merchantability, and fitness for a
+particular purpose, noninfringement, or arising from a course of dealing,
+usage or trade practice. Washington University, UC Irvine, Vanderbilt
+University, their employees, and students shall have no liability with respect
+to the infringement of copyrights, trade secrets or any patents by DOC
+software or any part thereof. Moreover, in no event will Washington
+University, UC Irvine, or Vanderbilt University, their employees, or students
+be liable for any lost revenue or profits or other special, indirect and
+consequential damages.
+
+DOC software is provided with no support and without any obligation on the
+part of Washington University, UC Irvine, Vanderbilt University, their
+employees, or students to assist in its use, correction, modification, or
+enhancement. A number of companies around the world provide commercial support
+for DOC software, however. DOC software is Y2K-compliant, as long as the
+underlying OS platform is Y2K-compliant. Likewise, DOC software is compliant
+with the new US daylight savings rule passed by Congress as "The Energy Policy
+Act of 2005," which established new daylight savings times (DST) rules for the
+United States that expand DST as of March 2007. Since DOC software obtains
+time/date and calendaring information from operating systems users will not be
+affected by the new DST rules as long as they upgrade their operating systems
+accordingly.
+
+The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), Washington
+University, UC Irvine, and Vanderbilt University, may not be used to endorse
+or promote products or services derived from this source without express
+written permission from Washington University, UC Irvine, or Vanderbilt
+University. This license grants no permission to call products or services
+derived from this source ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM),
+nor does it grant permission for the name Washington University, UC Irvine, or
+Vanderbilt University to appear in their names.
+*/
+
+/*
+ * 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.
+ */
+
+#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
+#include "webrtc/system_wrappers/source/critical_section_win.h"
+
+namespace webrtc {
+
+ConditionVariableEventWin::ConditionVariableEventWin() : eventID_(WAKEALL_0) {
+ memset(&num_waiters_[0], 0, sizeof(num_waiters_));
+
+ InitializeCriticalSection(&num_waiters_crit_sect_);
+
+ 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
+}
+
+ConditionVariableEventWin::~ConditionVariableEventWin() {
+ CloseHandle(events_[WAKE]);
+ CloseHandle(events_[WAKEALL_1]);
+ CloseHandle(events_[WAKEALL_0]);
+
+ DeleteCriticalSection(&num_waiters_crit_sect_);
+}
+
+void ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect) {
+ SleepCS(crit_sect, INFINITE);
+}
+
+bool ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect,
+ unsigned long max_time_in_ms) {
+ EnterCriticalSection(&num_waiters_crit_sect_);
+
+ // 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;
+
+ ++(num_waiters_[eventID]);
+ LeaveCriticalSection(&num_waiters_crit_sect_);
+
+ CriticalSectionWindows* cs =
+ static_cast<CriticalSectionWindows*>(&crit_sect);
+ 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.
+ max_time_in_ms);
+
+ const bool ret_val = (result != WAIT_TIMEOUT);
+
+ EnterCriticalSection(&num_waiters_crit_sect_);
+ --(num_waiters_[eventID]);
+
+ // Last waiter should only be true for WakeAll(). WakeAll() correspond
+ // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1)
+ const bool last_waiter = (result == WAIT_OBJECT_0 + 1) &&
+ (num_waiters_[eventID] == 0);
+ LeaveCriticalSection(&num_waiters_crit_sect_);
+
+ if (last_waiter) {
+ // Reset/unset the WakeAll() event since all threads have been
+ // released.
+ ResetEvent(events_[eventID]);
+ }
+
+ EnterCriticalSection(&cs->crit);
+ return ret_val;
+}
+
+void ConditionVariableEventWin::Wake() {
+ EnterCriticalSection(&num_waiters_crit_sect_);
+ const bool have_waiters = (num_waiters_[WAKEALL_0] > 0) ||
+ (num_waiters_[WAKEALL_1] > 0);
+ LeaveCriticalSection(&num_waiters_crit_sect_);
+
+ if (have_waiters) {
+ SetEvent(events_[WAKE]);
+ }
+}
+
+void ConditionVariableEventWin::WakeAll() {
+ EnterCriticalSection(&num_waiters_crit_sect_);
+
+ // Update current WakeAll() event
+ eventID_ = (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
+
+ // Trigger current event
+ const EventWakeUpType eventID = eventID_;
+ const bool have_waiters = num_waiters_[eventID] > 0;
+ LeaveCriticalSection(&num_waiters_crit_sect_);
+
+ if (have_waiters) {
+ SetEvent(events_[eventID]);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable_event_win.h b/webrtc/system_wrappers/source/condition_variable_event_win.h
new file mode 100644
index 0000000000..cdcef7dcb8
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable_event_win.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 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_EVENT_WIN_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_
+
+#include <windows.h>
+
+#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
+
+namespace webrtc {
+
+class ConditionVariableEventWin : public ConditionVariableWrapper {
+ public:
+ ConditionVariableEventWin();
+ virtual ~ConditionVariableEventWin();
+
+ void SleepCS(CriticalSectionWrapper& crit_sect);
+ bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS);
+ void Wake();
+ void WakeAll();
+
+ private:
+ enum EventWakeUpType {
+ WAKEALL_0 = 0,
+ WAKEALL_1 = 1,
+ WAKE = 2,
+ EVENT_COUNT = 3
+ };
+
+ unsigned int num_waiters_[2];
+ EventWakeUpType eventID_;
+ CRITICAL_SECTION num_waiters_crit_sect_;
+ HANDLE events_[EVENT_COUNT];
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_
diff --git a/webrtc/system_wrappers/source/condition_variable_native_win.cc b/webrtc/system_wrappers/source/condition_variable_native_win.cc
new file mode 100644
index 0000000000..45225f2016
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable_native_win.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2013 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 "webrtc/system_wrappers/include/trace.h"
+#include "webrtc/system_wrappers/source/condition_variable_native_win.h"
+#include "webrtc/system_wrappers/source/critical_section_win.h"
+
+namespace webrtc {
+
+static HMODULE library = NULL;
+static bool win_support_condition_variables_primitive = false;
+
+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);
+
+ConditionVariableNativeWin::ConditionVariableNativeWin() {
+}
+
+ConditionVariableNativeWin::~ConditionVariableNativeWin() {
+}
+
+ConditionVariableWrapper* ConditionVariableNativeWin::Create() {
+ ConditionVariableNativeWin* ret_val = new ConditionVariableNativeWin();
+ if (!ret_val->Init()) {
+ delete ret_val;
+ return NULL;
+ }
+ return ret_val;
+}
+
+bool ConditionVariableNativeWin::Init() {
+ if (!library) {
+ // Native implementation is supported on Vista+.
+ library = LoadLibrary(TEXT("Kernel32.dll"));
+ // TODO(henrike): this code results in an attempt to load the above dll
+ // every time the previous attempt failed. Only try to load once.
+ if (library) {
+ // TODO(henrike): not thread safe as reading and writing to library is not
+ // serialized. Fix.
+ 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");
+ win_support_condition_variables_primitive = true;
+ }
+ }
+ }
+ if (!win_support_condition_variables_primitive) {
+ return false;
+ }
+ PInitializeConditionVariable_(&condition_variable_);
+ return true;
+}
+
+void ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect) {
+ SleepCS(crit_sect, INFINITE);
+}
+
+bool ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect,
+ unsigned long max_time_in_ms) {
+ CriticalSectionWindows* cs =
+ static_cast<CriticalSectionWindows*>(&crit_sect);
+ BOOL ret_val = PSleepConditionVariableCS_(&condition_variable_,
+ &(cs->crit), max_time_in_ms);
+ return ret_val != 0;
+}
+
+void ConditionVariableNativeWin::Wake() {
+ PWakeConditionVariable_(&condition_variable_);
+}
+
+void ConditionVariableNativeWin::WakeAll() {
+ PWakeAllConditionVariable_(&condition_variable_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable_native_win.h b/webrtc/system_wrappers/source/condition_variable_native_win.h
new file mode 100644
index 0000000000..c22787f2f2
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable_native_win.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013 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_NATIVE_WIN_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_
+
+#include <windows.h>
+
+#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
+
+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 ConditionVariableNativeWin : public ConditionVariableWrapper {
+ public:
+ static ConditionVariableWrapper* Create();
+ virtual ~ConditionVariableNativeWin();
+
+ void SleepCS(CriticalSectionWrapper& crit_sect);
+ bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS);
+ void Wake();
+ void WakeAll();
+
+ private:
+ ConditionVariableNativeWin();
+
+ bool Init();
+
+ CONDITION_VARIABLE condition_variable_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_
diff --git a/webrtc/system_wrappers/source/condition_variable_posix.cc b/webrtc/system_wrappers/source/condition_variable_posix.cc
new file mode 100644
index 0000000000..b21304245c
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable_posix.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 "webrtc/system_wrappers/source/condition_variable_posix.h"
+
+#include <errno.h>
+#if defined(WEBRTC_LINUX)
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include "webrtc/system_wrappers/source/critical_section_posix.h"
+
+namespace webrtc {
+
+ConditionVariableWrapper* ConditionVariablePosix::Create() {
+ ConditionVariablePosix* ptr = new ConditionVariablePosix;
+ if (!ptr) {
+ return NULL;
+ }
+
+ const int error = ptr->Construct();
+ if (error) {
+ delete ptr;
+ return NULL;
+ }
+
+ return ptr;
+}
+
+ConditionVariablePosix::ConditionVariablePosix() {
+}
+
+int ConditionVariablePosix::Construct() {
+#ifdef WEBRTC_CLOCK_TYPE_REALTIME
+ pthread_cond_init(&cond_, NULL);
+#else
+ int result = 0;
+ pthread_condattr_t cond_attr;
+ result = pthread_condattr_init(&cond_attr);
+ if (result != 0) {
+ return -1;
+ }
+ result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
+ if (result != 0) {
+ return -1;
+ }
+ result = pthread_cond_init(&cond_, &cond_attr);
+ if (result != 0) {
+ return -1;
+ }
+ result = pthread_condattr_destroy(&cond_attr);
+ if (result != 0) {
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+ConditionVariablePosix::~ConditionVariablePosix() {
+ pthread_cond_destroy(&cond_);
+}
+
+void ConditionVariablePosix::SleepCS(CriticalSectionWrapper& crit_sect) {
+ CriticalSectionPosix* cs = reinterpret_cast<CriticalSectionPosix*>(
+ &crit_sect);
+ pthread_cond_wait(&cond_, &cs->mutex_);
+}
+
+bool ConditionVariablePosix::SleepCS(CriticalSectionWrapper& crit_sect,
+ unsigned long max_time_inMS) {
+ 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;
+
+ CriticalSectionPosix* cs = reinterpret_cast<CriticalSectionPosix*>(
+ &crit_sect);
+
+ if (max_time_inMS != INFINITE) {
+ timespec ts;
+#ifndef WEBRTC_MAC
+#ifdef WEBRTC_CLOCK_TYPE_REALTIME
+ clock_gettime(CLOCK_REALTIME, &ts);
+#else
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
+#else // WEBRTC_MAC
+ 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 += max_time_inMS / MILLISECONDS_PER_SECOND;
+ ts.tv_nsec +=
+ (max_time_inMS
+ - ((max_time_inMS / 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 ConditionVariablePosix::Wake() {
+ pthread_cond_signal(&cond_);
+}
+
+void ConditionVariablePosix::WakeAll() {
+ pthread_cond_broadcast(&cond_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/condition_variable_posix.h b/webrtc/system_wrappers/source/condition_variable_posix.h
new file mode 100644
index 0000000000..0aab1f03de
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable_posix.h
@@ -0,0 +1,42 @@
+/*
+ * 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_POSIX_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_
+
+#include <pthread.h>
+
+#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+class ConditionVariablePosix : public ConditionVariableWrapper {
+ public:
+ static ConditionVariableWrapper* Create();
+ ~ConditionVariablePosix() override;
+
+ void SleepCS(CriticalSectionWrapper& crit_sect) override;
+ bool SleepCS(CriticalSectionWrapper& crit_sect,
+ unsigned long max_time_in_ms) override;
+ void Wake() override;
+ void WakeAll() override;
+
+ private:
+ ConditionVariablePosix();
+ int Construct();
+
+ private:
+ pthread_cond_t cond_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_
diff --git a/webrtc/system_wrappers/source/condition_variable_unittest.cc b/webrtc/system_wrappers/source/condition_variable_unittest.cc
new file mode 100644
index 0000000000..ed845cc21e
--- /dev/null
+++ b/webrtc/system_wrappers/source/condition_variable_unittest.cc
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/condition_variable_wrapper.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/include/thread_wrapper.h"
+#include "webrtc/system_wrappers/include/tick_util.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+
+namespace {
+
+const int kLongWaitMs = 100 * 1000; // A long time in testing terms
+const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen
+const int kVeryShortWaitMs = 20; // Used when we want a timeout
+
+// A Baton is one possible control structure one can build using
+// conditional variables.
+// A Baton is always held by one and only one active thread - unlike
+// a lock, it can never be free.
+// One can pass it or grab it - both calls have timeouts.
+// Note - a production tool would guard against passing it without
+// grabbing it first. This one is for testing, so it doesn't.
+class Baton {
+ public:
+ Baton()
+ : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
+ crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
+ cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
+ being_passed_(false),
+ pass_count_(0) {
+ }
+
+ ~Baton() {
+ delete giver_sect_;
+ delete crit_sect_;
+ delete cond_var_;
+ }
+
+ // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
+ // Only one process can pass at the same time; this property is
+ // ensured by the |giver_sect_| lock.
+ bool Pass(uint32_t max_msecs) {
+ CriticalSectionScoped cs_giver(giver_sect_);
+ CriticalSectionScoped cs(crit_sect_);
+ SignalBatonAvailable();
+ const bool result = TakeBatonIfStillFree(max_msecs);
+ if (result) {
+ ++pass_count_;
+ }
+ return result;
+ }
+
+ // Grab the baton. Returns false if baton is not passed.
+ bool Grab(uint32_t max_msecs) {
+ CriticalSectionScoped cs(crit_sect_);
+ return WaitUntilBatonOffered(max_msecs);
+ }
+
+ int PassCount() {
+ // We don't allow polling PassCount() during a Pass()-call since there is
+ // no guarantee that |pass_count_| is incremented until the Pass()-call
+ // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
+ // incremented.
+ // Thus, this function waits on giver_sect_.
+ CriticalSectionScoped cs(giver_sect_);
+ return pass_count_;
+ }
+
+ private:
+ // Wait/Signal forms a classical semaphore on |being_passed_|.
+ // These functions must be called with crit_sect_ held.
+ bool WaitUntilBatonOffered(int timeout_ms) {
+ while (!being_passed_) {
+ if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
+ return false;
+ }
+ }
+ being_passed_ = false;
+ cond_var_->Wake();
+ return true;
+ }
+
+ void SignalBatonAvailable() {
+ assert(!being_passed_);
+ being_passed_ = true;
+ cond_var_->Wake();
+ }
+
+ // Timeout extension: Wait for a limited time for someone else to
+ // take it, and take it if it's not taken.
+ // Returns true if resource is taken by someone else, false
+ // if it is taken back by the caller.
+ // This function must be called with both |giver_sect_| and
+ // |crit_sect_| held.
+ bool TakeBatonIfStillFree(int timeout_ms) {
+ bool not_timeout = true;
+ while (being_passed_ && not_timeout) {
+ not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
+ // If we're woken up while variable is still held, we may have
+ // gotten a wakeup destined for a grabber thread.
+ // This situation is not treated specially here.
+ }
+ if (!being_passed_) {
+ return true;
+ } else {
+ assert(!not_timeout);
+ being_passed_ = false;
+ return false;
+ }
+ }
+
+ // Lock that ensures that there is only one thread in the active
+ // part of Pass() at a time.
+ // |giver_sect_| must always be acquired before |cond_var_|.
+ CriticalSectionWrapper* giver_sect_;
+ // Lock that protects |being_passed_|.
+ CriticalSectionWrapper* crit_sect_;
+ ConditionVariableWrapper* cond_var_;
+ bool being_passed_;
+ // Statistics information: Number of successfull passes.
+ int pass_count_;
+};
+
+// Function that waits on a Baton, and passes it right back.
+// We expect these calls never to time out.
+bool WaitingRunFunction(void* obj) {
+ Baton* the_baton = static_cast<Baton*> (obj);
+ EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
+ EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
+ return true;
+}
+
+class CondVarTest : public ::testing::Test {
+ public:
+ CondVarTest() {}
+
+ virtual void SetUp() {
+ thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
+ &baton_, "CondVarTest");
+ ASSERT_TRUE(thread_->Start());
+ }
+
+ virtual void TearDown() {
+ // We have to wake the thread in order to make it obey the stop order.
+ // But we don't know if the thread has completed the run function, so
+ // we don't know if it will exit before or after the Pass.
+ // Thus, we need to pin it down inside its Run function (between Grab
+ // and Pass).
+ ASSERT_TRUE(baton_.Pass(kShortWaitMs));
+ ASSERT_TRUE(baton_.Grab(kShortWaitMs));
+ ASSERT_TRUE(thread_->Stop());
+ }
+
+ protected:
+ Baton baton_;
+
+ private:
+ rtc::scoped_ptr<ThreadWrapper> thread_;
+};
+
+// The SetUp and TearDown functions use condition variables.
+// This test verifies those pieces in isolation.
+// Disabled due to flakiness. See bug 4262 for details.
+TEST_F(CondVarTest, DISABLED_InitFunctionsWork) {
+ // All relevant asserts are in the SetUp and TearDown functions.
+}
+
+// This test verifies that one can use the baton multiple times.
+TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
+ const int kNumberOfRounds = 2;
+ for (int i = 0; i < kNumberOfRounds; ++i) {
+ ASSERT_TRUE(baton_.Pass(kShortWaitMs));
+ ASSERT_TRUE(baton_.Grab(kShortWaitMs));
+ }
+ EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
+}
+
+TEST(CondVarWaitTest, WaitingWaits) {
+ rtc::scoped_ptr<CriticalSectionWrapper> crit_sect(
+ CriticalSectionWrapper::CreateCriticalSection());
+ rtc::scoped_ptr<ConditionVariableWrapper> cond_var(
+ ConditionVariableWrapper::CreateConditionVariable());
+ CriticalSectionScoped cs(crit_sect.get());
+ int64_t start_ms = TickTime::MillisecondTimestamp();
+ EXPECT_FALSE(cond_var->SleepCS(*(crit_sect), kVeryShortWaitMs));
+ int64_t end_ms = TickTime::MillisecondTimestamp();
+ EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms)
+ << "actual elapsed:" << end_ms - start_ms;
+}
+
+} // anonymous namespace
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/cpu_features.cc b/webrtc/system_wrappers/source/cpu_features.cc
new file mode 100644
index 0000000000..49840eb90d
--- /dev/null
+++ b/webrtc/system_wrappers/source/cpu_features.cc
@@ -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.
+ */
+
+// Parts of this file derived from Chromium's base/cpu.cc.
+
+#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
+
+#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
+#include <intrin.h>
+#endif
+
+#include "webrtc/typedefs.h"
+
+// No CPU feature is available => straight C path.
+int GetCPUInfoNoASM(CPUFeature feature) {
+ (void)feature;
+ return 0;
+}
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#ifndef _MSC_VER
+// 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));
+}
+#else
+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
+#endif // _MSC_VER
+#endif // WEBRTC_ARCH_X86_FAMILY
+
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+// 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/webrtc/system_wrappers/source/cpu_features_android.c b/webrtc/system_wrappers/source/cpu_features_android.c
new file mode 100644
index 0000000000..0cb3a6c5ee
--- /dev/null
+++ b/webrtc/system_wrappers/source/cpu_features_android.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2012 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.h>
+
+uint64_t WebRtc_GetCPUFeaturesARM(void) {
+ return android_getCpuFeatures();
+}
diff --git a/webrtc/system_wrappers/source/cpu_info.cc b/webrtc/system_wrappers/source/cpu_info.cc
new file mode 100644
index 0000000000..40231b65af
--- /dev/null
+++ b/webrtc/system_wrappers/source/cpu_info.cc
@@ -0,0 +1,21 @@
+/*
+ * 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 "webrtc/system_wrappers/include/cpu_info.h"
+
+#include "webrtc/base/systeminfo.h"
+
+namespace webrtc {
+
+uint32_t CpuInfo::DetectNumberOfCores() {
+ return static_cast<uint32_t>(rtc::SystemInfo::GetMaxCpus());
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section.cc b/webrtc/system_wrappers/source/critical_section.cc
new file mode 100644
index 0000000000..c5865887cd
--- /dev/null
+++ b/webrtc/system_wrappers/source/critical_section.cc
@@ -0,0 +1,28 @@
+/*
+ * 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 <windows.h>
+#include "webrtc/system_wrappers/source/critical_section_win.h"
+#else
+#include "webrtc/system_wrappers/source/critical_section_posix.h"
+#endif
+
+namespace webrtc {
+
+CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection() {
+#ifdef _WIN32
+ return new CriticalSectionWindows();
+#else
+ return new CriticalSectionPosix();
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section_posix.cc b/webrtc/system_wrappers/source/critical_section_posix.cc
new file mode 100644
index 0000000000..41b77327a3
--- /dev/null
+++ b/webrtc/system_wrappers/source/critical_section_posix.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+// General note: return values for the various pthread synchronization APIs
+// are explicitly ignored here. In Chromium, the same thing is done for release.
+// However, in debugging, failure in these APIs are logged.
+// TODO(henrike): add logging when pthread synchronization APIs are failing.
+
+#include "webrtc/system_wrappers/source/critical_section_posix.h"
+
+namespace webrtc {
+
+CriticalSectionPosix::CriticalSectionPosix() {
+ pthread_mutexattr_t attr;
+ (void) pthread_mutexattr_init(&attr);
+ (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ (void) pthread_mutex_init(&mutex_, &attr);
+}
+
+CriticalSectionPosix::~CriticalSectionPosix() {
+ (void) pthread_mutex_destroy(&mutex_);
+}
+
+void
+CriticalSectionPosix::Enter() {
+ (void) pthread_mutex_lock(&mutex_);
+}
+
+void
+CriticalSectionPosix::Leave() {
+ (void) pthread_mutex_unlock(&mutex_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section_posix.h b/webrtc/system_wrappers/source/critical_section_posix.h
new file mode 100644
index 0000000000..099f74c2df
--- /dev/null
+++ b/webrtc/system_wrappers/source/critical_section_posix.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_POSIX_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
+
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+
+#include <pthread.h>
+
+namespace webrtc {
+
+class CriticalSectionPosix : public CriticalSectionWrapper {
+ public:
+ CriticalSectionPosix();
+
+ ~CriticalSectionPosix() override;
+
+ void Enter() override;
+ void Leave() override;
+
+ private:
+ pthread_mutex_t mutex_;
+ friend class ConditionVariablePosix;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
diff --git a/webrtc/system_wrappers/source/critical_section_unittest.cc b/webrtc/system_wrappers/source/critical_section_unittest.cc
new file mode 100644
index 0000000000..6848bdd06b
--- /dev/null
+++ b/webrtc/system_wrappers/source/critical_section_unittest.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/critical_section_wrapper.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/system_wrappers/include/sleep.h"
+#include "webrtc/system_wrappers/include/thread_wrapper.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+
+namespace {
+
+// Cause a process switch. Needed to avoid depending on
+// busy-wait in tests.
+static void SwitchProcess() {
+ // Note - sched_yield has been tried as process switch. This does
+ // not cause a process switch enough of the time for reliability.
+ SleepMs(1);
+}
+
+class ProtectedCount {
+public:
+ explicit ProtectedCount(CriticalSectionWrapper* crit_sect)
+ : crit_sect_(crit_sect),
+ count_(0) {
+ }
+
+ void Increment() {
+ CriticalSectionScoped cs(crit_sect_);
+ ++count_;
+ }
+
+ int Count() const {
+ CriticalSectionScoped cs(crit_sect_);
+ return count_;
+ }
+
+private:
+ CriticalSectionWrapper* crit_sect_;
+ int count_;
+};
+
+class CritSectTest : public ::testing::Test {
+public:
+ CritSectTest() {}
+
+ // Waits a number of cycles for the count to reach a given value.
+ // Returns true if the target is reached or passed.
+ bool WaitForCount(int target, ProtectedCount* count) {
+ int loop_counter = 0;
+ // On Posix, this SwitchProcess() needs to be in a loop to make the
+ // test both fast and non-flaky.
+ // With 1 us wait as the switch, up to 7 rounds have been observed.
+ while (count->Count() < target && loop_counter < 100 * target) {
+ ++loop_counter;
+ SwitchProcess();
+ }
+ return (count->Count() >= target);
+ }
+};
+
+bool LockUnlockThenStopRunFunction(void* obj) {
+ ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
+ the_count->Increment();
+ return false;
+}
+
+TEST_F(CritSectTest, ThreadWakesOnce) NO_THREAD_SAFETY_ANALYSIS {
+ CriticalSectionWrapper* crit_sect =
+ CriticalSectionWrapper::CreateCriticalSection();
+ ProtectedCount count(crit_sect);
+ rtc::scoped_ptr<ThreadWrapper> thread = ThreadWrapper::CreateThread(
+ &LockUnlockThenStopRunFunction, &count, "ThreadWakesOnce");
+ crit_sect->Enter();
+ ASSERT_TRUE(thread->Start());
+ SwitchProcess();
+ // The critical section is of reentrant mode, so this should not release
+ // the lock, even though count.Count() locks and unlocks the critical section
+ // again.
+ // Thus, the thread should not be able to increment the count
+ ASSERT_EQ(0, count.Count());
+ crit_sect->Leave(); // This frees the thread to act.
+ EXPECT_TRUE(WaitForCount(1, &count));
+ EXPECT_TRUE(thread->Stop());
+ delete crit_sect;
+}
+
+bool LockUnlockRunFunction(void* obj) {
+ ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
+ the_count->Increment();
+ SwitchProcess();
+ return true;
+}
+
+TEST_F(CritSectTest, ThreadWakesTwice) NO_THREAD_SAFETY_ANALYSIS {
+ CriticalSectionWrapper* crit_sect =
+ CriticalSectionWrapper::CreateCriticalSection();
+ ProtectedCount count(crit_sect);
+ rtc::scoped_ptr<ThreadWrapper> thread = ThreadWrapper::CreateThread(
+ &LockUnlockRunFunction, &count, "ThreadWakesTwice");
+ crit_sect->Enter(); // Make sure counter stays 0 until we wait for it.
+ ASSERT_TRUE(thread->Start());
+ crit_sect->Leave();
+
+ // The thread is capable of grabbing the lock multiple times,
+ // incrementing counter once each time.
+ // It's possible for the count to be incremented by more than 2.
+ EXPECT_TRUE(WaitForCount(2, &count));
+ EXPECT_LE(2, count.Count());
+
+ // The thread does not increment while lock is held.
+ crit_sect->Enter();
+ int count_before = count.Count();
+ for (int i = 0; i < 10; i++) {
+ SwitchProcess();
+ }
+ EXPECT_EQ(count_before, count.Count());
+ crit_sect->Leave();
+
+ SwitchProcess();
+ EXPECT_TRUE(WaitForCount(count_before + 1, &count));
+ EXPECT_TRUE(thread->Stop());
+ delete crit_sect;
+}
+
+} // anonymous namespace
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/critical_section_win.cc b/webrtc/system_wrappers/source/critical_section_win.cc
new file mode 100644
index 0000000000..b5149d1eb6
--- /dev/null
+++ b/webrtc/system_wrappers/source/critical_section_win.cc
@@ -0,0 +1,33 @@
+/*
+ * 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 "webrtc/system_wrappers/source/critical_section_win.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/webrtc/system_wrappers/source/critical_section_win.h b/webrtc/system_wrappers/source/critical_section_win.h
new file mode 100644
index 0000000000..8268bc3017
--- /dev/null
+++ b/webrtc/system_wrappers/source/critical_section_win.h
@@ -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.
+ */
+
+#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
+
+#include <windows.h>
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+class CriticalSectionWindows : public CriticalSectionWrapper {
+ public:
+ CriticalSectionWindows();
+
+ virtual ~CriticalSectionWindows();
+
+ virtual void Enter();
+ virtual void Leave();
+
+ private:
+ CRITICAL_SECTION crit;
+
+ friend class ConditionVariableEventWin;
+ friend class ConditionVariableNativeWin;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
diff --git a/webrtc/system_wrappers/source/data_log.cc b/webrtc/system_wrappers/source/data_log.cc
new file mode 100644
index 0000000000..dbc8ea1505
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log.cc
@@ -0,0 +1,444 @@
+/*
+ * 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 "webrtc/system_wrappers/include/data_log.h"
+
+#include <assert.h>
+
+#include <algorithm>
+#include <list>
+
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/include/event_wrapper.h"
+#include "webrtc/system_wrappers/include/file_wrapper.h"
+#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+
+namespace webrtc {
+
+DataLogImpl::CritSectScopedPtr DataLogImpl::crit_sect_(
+ CriticalSectionWrapper::CreateCriticalSection());
+
+DataLogImpl* DataLogImpl::instance_ = NULL;
+
+// A Row contains cells, which are indexed by the column names as std::string.
+// The string index is treated in a case sensitive way.
+class Row {
+ public:
+ Row();
+ ~Row();
+
+ // Inserts a Container into the cell of the column specified with
+ // column_name.
+ // column_name is treated in a case sensitive way.
+ int InsertCell(const std::string& column_name,
+ const Container* value_container);
+
+ // Converts the value at the column specified by column_name to a string
+ // stored in value_string.
+ // column_name is treated in a case sensitive way.
+ void ToString(const std::string& column_name, std::string* value_string);
+
+ private:
+ // Collection of containers indexed by column name as std::string
+ typedef std::map<std::string, const Container*> CellMap;
+
+ CellMap cells_;
+ CriticalSectionWrapper* cells_lock_;
+};
+
+// A LogTable contains multiple rows, where only the latest row is active for
+// editing. The rows are defined by the ColumnMap, which contains the name of
+// each column and the length of the column (1 for one-value-columns and greater
+// than 1 for multi-value-columns).
+class LogTable {
+ public:
+ LogTable();
+ ~LogTable();
+
+ // Adds the column with name column_name to the table. The column will be a
+ // multi-value-column if multi_value_length is greater than 1.
+ // column_name is treated in a case sensitive way.
+ int AddColumn(const std::string& column_name, int multi_value_length);
+
+ // Buffers the current row while it is waiting to be written to file,
+ // which is done by a call to Flush(). A new row is available when the
+ // function returns
+ void NextRow();
+
+ // Inserts a Container into the cell of the column specified with
+ // column_name.
+ // column_name is treated in a case sensitive way.
+ int InsertCell(const std::string& column_name,
+ const Container* value_container);
+
+ // Creates a log file, named as specified in the string file_name, to
+ // where the table will be written when calling Flush().
+ int CreateLogFile(const std::string& file_name);
+
+ // Write all complete rows to file.
+ // May not be called by two threads simultaneously (doing so may result in
+ // a race condition). Will be called by the file_writer_thread_ when that
+ // thread is running.
+ void Flush();
+
+ private:
+ // Collection of multi_value_lengths indexed by column name as std::string
+ typedef std::map<std::string, int> ColumnMap;
+ typedef std::list<Row*> RowList;
+
+ ColumnMap columns_;
+ RowList rows_[2];
+ RowList* rows_history_;
+ RowList* rows_flush_;
+ Row* current_row_;
+ FileWrapper* file_;
+ bool write_header_;
+ CriticalSectionWrapper* table_lock_;
+};
+
+Row::Row()
+ : cells_(),
+ cells_lock_(CriticalSectionWrapper::CreateCriticalSection()) {
+}
+
+Row::~Row() {
+ for (CellMap::iterator it = cells_.begin(); it != cells_.end();) {
+ delete it->second;
+ // For maps all iterators (except the erased) are valid after an erase
+ cells_.erase(it++);
+ }
+ delete cells_lock_;
+}
+
+int Row::InsertCell(const std::string& column_name,
+ const Container* value_container) {
+ CriticalSectionScoped synchronize(cells_lock_);
+ assert(cells_.count(column_name) == 0);
+ if (cells_.count(column_name) > 0)
+ return -1;
+ cells_[column_name] = value_container;
+ return 0;
+}
+
+void Row::ToString(const std::string& column_name,
+ std::string* value_string) {
+ CriticalSectionScoped synchronize(cells_lock_);
+ const Container* container = cells_[column_name];
+ if (container == NULL) {
+ *value_string = "NaN,";
+ return;
+ }
+ container->ToString(value_string);
+}
+
+LogTable::LogTable()
+ : columns_(),
+ rows_(),
+ rows_history_(&rows_[0]),
+ rows_flush_(&rows_[1]),
+ current_row_(new Row),
+ file_(FileWrapper::Create()),
+ write_header_(true),
+ table_lock_(CriticalSectionWrapper::CreateCriticalSection()) {
+}
+
+LogTable::~LogTable() {
+ for (RowList::iterator row_it = rows_history_->begin();
+ row_it != rows_history_->end();) {
+ delete *row_it;
+ row_it = rows_history_->erase(row_it);
+ }
+ for (ColumnMap::iterator col_it = columns_.begin();
+ col_it != columns_.end();) {
+ // For maps all iterators (except the erased) are valid after an erase
+ columns_.erase(col_it++);
+ }
+ if (file_ != NULL) {
+ file_->Flush();
+ file_->CloseFile();
+ delete file_;
+ }
+ delete current_row_;
+ delete table_lock_;
+}
+
+int LogTable::AddColumn(const std::string& column_name,
+ int multi_value_length) {
+ assert(multi_value_length > 0);
+ if (!write_header_) {
+ // It's not allowed to add new columns after the header
+ // has been written.
+ assert(false);
+ return -1;
+ } else {
+ CriticalSectionScoped synchronize(table_lock_);
+ if (write_header_)
+ columns_[column_name] = multi_value_length;
+ else
+ return -1;
+ }
+ return 0;
+}
+
+void LogTable::NextRow() {
+ CriticalSectionScoped sync_rows(table_lock_);
+ rows_history_->push_back(current_row_);
+ current_row_ = new Row;
+}
+
+int LogTable::InsertCell(const std::string& column_name,
+ const Container* value_container) {
+ CriticalSectionScoped synchronize(table_lock_);
+ assert(columns_.count(column_name) > 0);
+ if (columns_.count(column_name) == 0)
+ return -1;
+ return current_row_->InsertCell(column_name, value_container);
+}
+
+int LogTable::CreateLogFile(const std::string& file_name) {
+ if (file_name.length() == 0)
+ return -1;
+ if (file_->Open())
+ return -1;
+ file_->OpenFile(file_name.c_str(),
+ false, // Open with read/write permissions
+ false, // Don't wraparound and write at the beginning when
+ // the file is full
+ true); // Open as a text file
+ if (file_ == NULL)
+ return -1;
+ return 0;
+}
+
+void LogTable::Flush() {
+ ColumnMap::iterator column_it;
+ bool commit_header = false;
+ if (write_header_) {
+ CriticalSectionScoped synchronize(table_lock_);
+ if (write_header_) {
+ commit_header = true;
+ write_header_ = false;
+ }
+ }
+ if (commit_header) {
+ for (column_it = columns_.begin();
+ column_it != columns_.end(); ++column_it) {
+ if (column_it->second > 1) {
+ file_->WriteText("%s[%u],", column_it->first.c_str(),
+ column_it->second);
+ for (int i = 1; i < column_it->second; ++i)
+ file_->WriteText(",");
+ } else {
+ file_->WriteText("%s,", column_it->first.c_str());
+ }
+ }
+ if (columns_.size() > 0)
+ file_->WriteText("\n");
+ }
+
+ // Swap the list used for flushing with the list containing the row history
+ // and clear the history. We also create a local pointer to the new
+ // list used for flushing to avoid race conditions if another thread
+ // calls this function while we are writing.
+ // We don't want to block the list while we're writing to file.
+ {
+ CriticalSectionScoped synchronize(table_lock_);
+ RowList* tmp = rows_flush_;
+ rows_flush_ = rows_history_;
+ rows_history_ = tmp;
+ rows_history_->clear();
+ }
+
+ // Write all complete rows to file and delete them
+ for (RowList::iterator row_it = rows_flush_->begin();
+ row_it != rows_flush_->end();) {
+ for (column_it = columns_.begin();
+ column_it != columns_.end(); ++column_it) {
+ std::string row_string;
+ (*row_it)->ToString(column_it->first, &row_string);
+ file_->WriteText("%s", row_string.c_str());
+ }
+ if (columns_.size() > 0)
+ file_->WriteText("\n");
+ delete *row_it;
+ row_it = rows_flush_->erase(row_it);
+ }
+}
+
+int DataLog::CreateLog() {
+ return DataLogImpl::CreateLog();
+}
+
+void DataLog::ReturnLog() {
+ return DataLogImpl::ReturnLog();
+}
+
+std::string DataLog::Combine(const std::string& table_name, int table_id) {
+ std::stringstream ss;
+ std::string combined_id = table_name;
+ std::string number_suffix;
+ ss << "_" << table_id;
+ ss >> number_suffix;
+ combined_id += number_suffix;
+ std::transform(combined_id.begin(), combined_id.end(), combined_id.begin(),
+ ::tolower);
+ return combined_id;
+}
+
+int DataLog::AddTable(const std::string& table_name) {
+ DataLogImpl* data_log = DataLogImpl::StaticInstance();
+ if (data_log == NULL)
+ return -1;
+ return data_log->AddTable(table_name);
+}
+
+int DataLog::AddColumn(const std::string& table_name,
+ const std::string& column_name,
+ int multi_value_length) {
+ DataLogImpl* data_log = DataLogImpl::StaticInstance();
+ if (data_log == NULL)
+ return -1;
+ return data_log->DataLogImpl::StaticInstance()->AddColumn(table_name,
+ column_name,
+ multi_value_length);
+}
+
+int DataLog::NextRow(const std::string& table_name) {
+ DataLogImpl* data_log = DataLogImpl::StaticInstance();
+ if (data_log == NULL)
+ return -1;
+ return data_log->DataLogImpl::StaticInstance()->NextRow(table_name);
+}
+
+DataLogImpl::DataLogImpl()
+ : counter_(1),
+ tables_(),
+ flush_event_(EventWrapper::Create()),
+ tables_lock_(RWLockWrapper::CreateRWLock()) {
+}
+
+DataLogImpl::~DataLogImpl() {
+ StopThread();
+ Flush(); // Write any remaining rows
+ delete flush_event_;
+ for (TableMap::iterator it = tables_.begin(); it != tables_.end();) {
+ delete static_cast<LogTable*>(it->second);
+ // For maps all iterators (except the erased) are valid after an erase
+ tables_.erase(it++);
+ }
+ delete tables_lock_;
+}
+
+int DataLogImpl::CreateLog() {
+ CriticalSectionScoped synchronize(crit_sect_.get());
+ if (instance_ == NULL) {
+ instance_ = new DataLogImpl();
+ return instance_->Init();
+ } else {
+ ++instance_->counter_;
+ }
+ return 0;
+}
+
+int DataLogImpl::Init() {
+ file_writer_thread_ = ThreadWrapper::CreateThread(
+ DataLogImpl::Run, instance_, "DataLog");
+ bool success = file_writer_thread_->Start();
+ if (!success)
+ return -1;
+ file_writer_thread_->SetPriority(kHighestPriority);
+ return 0;
+}
+
+DataLogImpl* DataLogImpl::StaticInstance() {
+ return instance_;
+}
+
+void DataLogImpl::ReturnLog() {
+ CriticalSectionScoped synchronize(crit_sect_.get());
+ if (instance_ && instance_->counter_ > 1) {
+ --instance_->counter_;
+ return;
+ }
+ delete instance_;
+ instance_ = NULL;
+}
+
+int DataLogImpl::AddTable(const std::string& table_name) {
+ WriteLockScoped synchronize(*tables_lock_);
+ // Make sure we don't add a table which already exists
+ if (tables_.count(table_name) > 0)
+ return -1;
+ tables_[table_name] = new LogTable();
+ if (tables_[table_name]->CreateLogFile(table_name + ".txt") == -1)
+ return -1;
+ return 0;
+}
+
+int DataLogImpl::AddColumn(const std::string& table_name,
+ const std::string& column_name,
+ int multi_value_length) {
+ ReadLockScoped synchronize(*tables_lock_);
+ if (tables_.count(table_name) == 0)
+ return -1;
+ return tables_[table_name]->AddColumn(column_name, multi_value_length);
+}
+
+int DataLogImpl::InsertCell(const std::string& table_name,
+ const std::string& column_name,
+ const Container* value_container) {
+ ReadLockScoped synchronize(*tables_lock_);
+ assert(tables_.count(table_name) > 0);
+ if (tables_.count(table_name) == 0)
+ return -1;
+ return tables_[table_name]->InsertCell(column_name, value_container);
+}
+
+int DataLogImpl::NextRow(const std::string& table_name) {
+ ReadLockScoped synchronize(*tables_lock_);
+ if (tables_.count(table_name) == 0)
+ return -1;
+ tables_[table_name]->NextRow();
+ if (!file_writer_thread_) {
+ // Write every row to file as they get complete.
+ tables_[table_name]->Flush();
+ } else {
+ // Signal a complete row
+ flush_event_->Set();
+ }
+ return 0;
+}
+
+void DataLogImpl::Flush() {
+ ReadLockScoped synchronize(*tables_lock_);
+ for (TableMap::iterator it = tables_.begin(); it != tables_.end(); ++it) {
+ it->second->Flush();
+ }
+}
+
+bool DataLogImpl::Run(void* obj) {
+ static_cast<DataLogImpl*>(obj)->Process();
+ return true;
+}
+
+void DataLogImpl::Process() {
+ // Wait for a row to be complete
+ flush_event_->Wait(WEBRTC_EVENT_INFINITE);
+ Flush();
+}
+
+void DataLogImpl::StopThread() {
+ if (file_writer_thread_) {
+ flush_event_->Set();
+ file_writer_thread_->Stop();
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/data_log_c.cc b/webrtc/system_wrappers/source/data_log_c.cc
new file mode 100644
index 0000000000..12a0d3f61a
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log_c.cc
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+// This is the pure C wrapper of the DataLog class.
+
+#include "webrtc/system_wrappers/include/data_log_c.h"
+
+#include <string>
+
+#include "webrtc/system_wrappers/include/data_log.h"
+
+extern "C" int WebRtcDataLog_CreateLog() {
+ return webrtc::DataLog::CreateLog();
+}
+
+extern "C" void WebRtcDataLog_ReturnLog() {
+ return webrtc::DataLog::ReturnLog();
+}
+
+extern "C" char* WebRtcDataLog_Combine(char* combined_name, size_t combined_len,
+ const char* table_name, int table_id) {
+ if (!table_name) return NULL;
+ std::string combined = webrtc::DataLog::Combine(table_name, table_id);
+ if (combined.size() >= combined_len) return NULL;
+ std::copy(combined.begin(), combined.end(), combined_name);
+ combined_name[combined.size()] = '\0';
+ return combined_name;
+}
+
+extern "C" int WebRtcDataLog_AddTable(const char* table_name) {
+ if (!table_name) return -1;
+ return webrtc::DataLog::AddTable(table_name);
+}
+
+extern "C" int WebRtcDataLog_AddColumn(const char* table_name,
+ const char* column_name,
+ int multi_value_length) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::AddColumn(table_name, column_name,
+ multi_value_length);
+}
+
+extern "C" int WebRtcDataLog_InsertCell_int(const char* table_name,
+ const char* column_name,
+ int value) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, value);
+}
+
+extern "C" int WebRtcDataLog_InsertArray_int(const char* table_name,
+ const char* column_name,
+ const int* values,
+ int length) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
+}
+
+extern "C" int WebRtcDataLog_InsertCell_float(const char* table_name,
+ const char* column_name,
+ float value) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, value);
+}
+
+extern "C" int WebRtcDataLog_InsertArray_float(const char* table_name,
+ const char* column_name,
+ const float* values,
+ int length) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
+}
+
+extern "C" int WebRtcDataLog_InsertCell_double(const char* table_name,
+ const char* column_name,
+ double value) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, value);
+}
+
+extern "C" int WebRtcDataLog_InsertArray_double(const char* table_name,
+ const char* column_name,
+ const double* values,
+ int length) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
+}
+
+extern "C" int WebRtcDataLog_InsertCell_int32(const char* table_name,
+ const char* column_name,
+ int32_t value) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, value);
+}
+
+extern "C" int WebRtcDataLog_InsertArray_int32(const char* table_name,
+ const char* column_name,
+ const int32_t* values,
+ int length) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
+}
+
+extern "C" int WebRtcDataLog_InsertCell_uint32(const char* table_name,
+ const char* column_name,
+ uint32_t value) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, value);
+}
+
+extern "C" int WebRtcDataLog_InsertArray_uint32(const char* table_name,
+ const char* column_name,
+ const uint32_t* values,
+ int length) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
+}
+
+extern "C" int WebRtcDataLog_InsertCell_int64(const char* table_name,
+ const char* column_name,
+ int64_t value) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, value);
+}
+
+extern "C" int WebRtcDataLog_InsertArray_int64(const char* table_name,
+ const char* column_name,
+ const int64_t* values,
+ int length) {
+ if (!table_name || !column_name) return -1;
+ return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
+}
+
+extern "C" int WebRtcDataLog_NextRow(const char* table_name) {
+ if (!table_name) return -1;
+ return webrtc::DataLog::NextRow(table_name);
+}
diff --git a/webrtc/system_wrappers/source/data_log_c_helpers_unittest.c b/webrtc/system_wrappers/source/data_log_c_helpers_unittest.c
new file mode 100644
index 0000000000..0b05e224eb
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log_c_helpers_unittest.c
@@ -0,0 +1,124 @@
+/*
+ * 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 "webrtc/system_wrappers/source/data_log_c_helpers_unittest.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "webrtc/system_wrappers/include/data_log_c.h"
+
+enum { kTestArrayLen = 4 };
+static const char kTableName[] = "c_wrapper_table";
+static const char kColumnName1[] = "Scalar";
+static const char kColumnName2[] = "Vector";
+
+int WebRtcDataLogCHelper_TestCreateLog() {
+ return WebRtcDataLog_CreateLog();
+}
+
+int WebRtcDataLogCHelper_TestReturnLog() {
+ WebRtcDataLog_ReturnLog();
+ return 0;
+}
+
+int WebRtcDataLogCHelper_TestCombine() {
+ const int kOutLen = strlen(kTableName) + 4; // Room for "_17" + '\0'
+ char* combined_name = malloc(kOutLen * sizeof(char));
+ char* out_ptr = WebRtcDataLog_Combine(combined_name, kOutLen, kTableName, 17);
+ int return_code = 0;
+ if (!out_ptr) {
+ return_code = -1;
+ }
+ if (strcmp(combined_name, "c_wrapper_table_17") != 0) {
+ return_code = -2;
+ }
+ free(combined_name);
+ return return_code;
+}
+
+int WebRtcDataLogCHelper_TestAddTable() {
+ return WebRtcDataLog_AddTable(kTableName);
+}
+
+int WebRtcDataLogCHelper_TestAddColumn() {
+ if (WebRtcDataLog_AddColumn(kTableName, kColumnName1, 1) != 0) {
+ return -1;
+ }
+ if (WebRtcDataLog_AddColumn(kTableName, kColumnName2, kTestArrayLen) != 0) {
+ return -2;
+ }
+ return 0;
+}
+
+int WebRtcDataLogCHelper_TestNextRow() {
+ return WebRtcDataLog_NextRow(kTableName);
+}
+
+int WebRtcDataLogCHelper_TestInsertCell_int() {
+ return WebRtcDataLog_InsertCell_int(kTableName, kColumnName1, 17);
+}
+
+int WebRtcDataLogCHelper_TestInsertArray_int() {
+ int values[kTestArrayLen] = {1, 2, 3, 4};
+ return WebRtcDataLog_InsertArray_int(kTableName, kColumnName2, values,
+ kTestArrayLen);
+}
+
+int WebRtcDataLogCHelper_TestInsertCell_float() {
+ return WebRtcDataLog_InsertCell_float(kTableName, kColumnName1, 17.0f);
+}
+
+int WebRtcDataLogCHelper_TestInsertArray_float() {
+ float values[kTestArrayLen] = {1.0f, 2.0f, 3.0f, 4.0f};
+ return WebRtcDataLog_InsertArray_float(kTableName, kColumnName2, values,
+ kTestArrayLen);
+}
+
+int WebRtcDataLogCHelper_TestInsertCell_double() {
+ return WebRtcDataLog_InsertCell_int(kTableName, kColumnName1, 17.0);
+}
+
+int WebRtcDataLogCHelper_TestInsertArray_double() {
+ double values[kTestArrayLen] = {1.0, 2.0, 3.0, 4.0};
+ return WebRtcDataLog_InsertArray_double(kTableName, kColumnName2, values,
+ kTestArrayLen);
+}
+
+int WebRtcDataLogCHelper_TestInsertCell_int32() {
+ return WebRtcDataLog_InsertCell_int32(kTableName, kColumnName1, 17);
+}
+
+int WebRtcDataLogCHelper_TestInsertArray_int32() {
+ int32_t values[kTestArrayLen] = {1, 2, 3, 4};
+ return WebRtcDataLog_InsertArray_int32(kTableName, kColumnName2, values,
+ kTestArrayLen);
+}
+
+int WebRtcDataLogCHelper_TestInsertCell_uint32() {
+ return WebRtcDataLog_InsertCell_uint32(kTableName, kColumnName1, 17);
+}
+
+int WebRtcDataLogCHelper_TestInsertArray_uint32() {
+ uint32_t values[kTestArrayLen] = {1, 2, 3, 4};
+ return WebRtcDataLog_InsertArray_uint32(kTableName, kColumnName2, values,
+ kTestArrayLen);
+}
+
+int WebRtcDataLogCHelper_TestInsertCell_int64() {
+ return WebRtcDataLog_InsertCell_int64(kTableName, kColumnName1, 17);
+}
+
+int WebRtcDataLogCHelper_TestInsertArray_int64() {
+ int64_t values[kTestArrayLen] = {1, 2, 3, 4};
+ return WebRtcDataLog_InsertArray_int64(kTableName, kColumnName2, values,
+ kTestArrayLen);
+}
diff --git a/webrtc/system_wrappers/source/data_log_c_helpers_unittest.h b/webrtc/system_wrappers/source/data_log_c_helpers_unittest.h
new file mode 100644
index 0000000000..ef86eae0b1
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log_c_helpers_unittest.h
@@ -0,0 +1,58 @@
+/*
+ * 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 SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_
+#define SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int WebRtcDataLogCHelper_TestCreateLog();
+
+int WebRtcDataLogCHelper_TestReturnLog();
+
+int WebRtcDataLogCHelper_TestCombine();
+
+int WebRtcDataLogCHelper_TestAddTable();
+
+int WebRtcDataLogCHelper_TestAddColumn();
+
+int WebRtcDataLogCHelper_TestNextRow();
+
+int WebRtcDataLogCHelper_TestInsertCell_int();
+
+int WebRtcDataLogCHelper_TestInsertArray_int();
+
+int WebRtcDataLogCHelper_TestInsertCell_float();
+
+int WebRtcDataLogCHelper_TestInsertArray_float();
+
+int WebRtcDataLogCHelper_TestInsertCell_double();
+
+int WebRtcDataLogCHelper_TestInsertArray_double();
+
+int WebRtcDataLogCHelper_TestInsertCell_int32();
+
+int WebRtcDataLogCHelper_TestInsertArray_int32();
+
+int WebRtcDataLogCHelper_TestInsertCell_uint32();
+
+int WebRtcDataLogCHelper_TestInsertArray_uint32();
+
+int WebRtcDataLogCHelper_TestInsertCell_int64();
+
+int WebRtcDataLogCHelper_TestInsertArray_int64();
+
+#ifdef __cplusplus
+} // end of extern "C"
+#endif
+
+#endif // SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_
diff --git a/webrtc/system_wrappers/source/data_log_helpers_unittest.cc b/webrtc/system_wrappers/source/data_log_helpers_unittest.cc
new file mode 100644
index 0000000000..25e1827ddb
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log_helpers_unittest.cc
@@ -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 "webrtc/system_wrappers/include/data_log.h"
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::webrtc::DataLog;
+
+TEST(TestDataLog, IntContainers) {
+ int c = 5;
+ webrtc::ValueContainer<int> v1(c);
+ c = 10;
+ webrtc::ValueContainer<int> v2(c);
+ std::string s1, s2;
+ v1.ToString(&s1);
+ v2.ToString(&s2);
+ ASSERT_EQ(s1, "5,");
+ ASSERT_EQ(s2, "10,");
+ v1 = v2;
+ v1.ToString(&s1);
+ ASSERT_EQ(s1, s2);
+}
+
+TEST(TestDataLog, DoubleContainers) {
+ double c = 3.5;
+ webrtc::ValueContainer<double> v1(c);
+ c = 10.3;
+ webrtc::ValueContainer<double> v2(c);
+ std::string s1, s2;
+ v1.ToString(&s1);
+ v2.ToString(&s2);
+ ASSERT_EQ(s1, "3.5,");
+ ASSERT_EQ(s2, "10.3,");
+ v1 = v2;
+ v1.ToString(&s1);
+ ASSERT_EQ(s1, s2);
+}
+
+TEST(TestDataLog, MultiValueContainers) {
+ int a[3] = {1, 2, 3};
+ int b[3] = {4, 5, 6};
+ webrtc::MultiValueContainer<int> m1(a, 3);
+ webrtc::MultiValueContainer<int> m2(b, 3);
+ webrtc::MultiValueContainer<int> m3(a, 3);
+ std::string s1, s2, s3;
+ m1.ToString(&s1);
+ m2.ToString(&s2);
+ ASSERT_EQ(s1, "1,2,3,");
+ ASSERT_EQ(s2, "4,5,6,");
+ m1 = m2;
+ m1.ToString(&s1);
+ ASSERT_EQ(s1, s2);
+ m3.ToString(&s3);
+ ASSERT_EQ(s3, "1,2,3,");
+}
diff --git a/webrtc/system_wrappers/source/data_log_no_op.cc b/webrtc/system_wrappers/source/data_log_no_op.cc
new file mode 100644
index 0000000000..bdd2b0a403
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log_no_op.cc
@@ -0,0 +1,88 @@
+/*
+ * 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 "webrtc/system_wrappers/include/data_log.h"
+
+#include <string>
+
+namespace webrtc {
+
+int DataLog::CreateLog() {
+ return 0;
+}
+
+void DataLog::ReturnLog() {
+}
+
+std::string DataLog::Combine(const std::string& table_name, int table_id) {
+ return std::string();
+}
+
+int DataLog::AddTable(const std::string& /*table_name*/) {
+ return 0;
+}
+
+int DataLog::AddColumn(const std::string& /*table_name*/,
+ const std::string& /*column_name*/,
+ int /*multi_value_length*/) {
+ return 0;
+}
+
+int DataLog::NextRow(const std::string& /*table_name*/) {
+ return 0;
+}
+
+DataLogImpl::DataLogImpl() {
+}
+
+DataLogImpl::~DataLogImpl() {
+}
+
+DataLogImpl* DataLogImpl::StaticInstance() {
+ return NULL;
+}
+
+void DataLogImpl::ReturnLog() {
+}
+
+int DataLogImpl::AddTable(const std::string& /*table_name*/) {
+ return 0;
+}
+
+int DataLogImpl::AddColumn(const std::string& /*table_name*/,
+ const std::string& /*column_name*/,
+ int /*multi_value_length*/) {
+ return 0;
+}
+
+int DataLogImpl::InsertCell(const std::string& /*table_name*/,
+ const std::string& /*column_name*/,
+ const Container* /*value_container*/) {
+ return 0;
+}
+
+int DataLogImpl::NextRow(const std::string& /*table_name*/) {
+ return 0;
+}
+
+void DataLogImpl::Flush() {
+}
+
+bool DataLogImpl::Run(void* /*obj*/) {
+ return true;
+}
+
+void DataLogImpl::Process() {
+}
+
+void DataLogImpl::StopThread() {
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/data_log_unittest.cc b/webrtc/system_wrappers/source/data_log_unittest.cc
new file mode 100644
index 0000000000..53f201ca5f
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log_unittest.cc
@@ -0,0 +1,311 @@
+/*
+ * 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 "webrtc/system_wrappers/include/data_log.h"
+
+#include <map>
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/system_wrappers/include/data_log_c.h"
+#include "webrtc/system_wrappers/source/data_log_c_helpers_unittest.h"
+
+using ::webrtc::DataLog;
+
+// A class for storing the values expected from a log table column when
+// verifying a log table file.
+struct ExpectedValues {
+ public:
+ ExpectedValues()
+ : values(),
+ multi_value_length(1) {
+ }
+
+ ExpectedValues(std::vector<std::string> expected_values,
+ int expected_multi_value_length)
+ : values(expected_values),
+ multi_value_length(expected_multi_value_length) {
+ }
+
+ std::vector<std::string> values;
+ int multi_value_length;
+};
+
+typedef std::map<std::string, ExpectedValues> ExpectedValuesMap;
+
+// A static class used for parsing and verifying data log files.
+class DataLogParser {
+ public:
+ // Verifies that the log table stored in the file "log_file" corresponds to
+ // the cells and columns specified in "columns".
+ static int VerifyTable(FILE* log_file, const ExpectedValuesMap& columns) {
+ int row = 0;
+ char line_buffer[kMaxLineLength];
+ char* ret = fgets(line_buffer, kMaxLineLength, log_file);
+ EXPECT_FALSE(ret == NULL);
+ if (ret == NULL)
+ return -1;
+
+ std::string line(line_buffer, kMaxLineLength);
+ VerifyHeader(line, columns);
+ while (fgets(line_buffer, kMaxLineLength, log_file) != NULL) {
+ line = std::string(line_buffer, kMaxLineLength);
+ size_t line_position = 0;
+
+ for (ExpectedValuesMap::const_iterator it = columns.begin();
+ it != columns.end(); ++it) {
+ std::string str = ParseElement(line, &line_position,
+ it->second.multi_value_length);
+ EXPECT_EQ(str, it->second.values[row]);
+ if (str != it->second.values[row])
+ return -1;
+ }
+ ++row;
+ }
+ return 0;
+ }
+
+ // Verifies the table header stored in "line" to correspond with the header
+ // specified in "columns".
+ static int VerifyHeader(const std::string& line,
+ const ExpectedValuesMap& columns) {
+ size_t line_position = 0;
+ for (ExpectedValuesMap::const_iterator it = columns.begin();
+ it != columns.end(); ++it) {
+ std::string str = ParseElement(line, &line_position,
+ it->second.multi_value_length);
+ EXPECT_EQ(str, it->first);
+ if (str != it->first)
+ return -1;
+ }
+ return 0;
+ }
+
+ // Parses out and returns one element from the string "line", which contains
+ // one line read from a log table file. An element can either be a column
+ // header or a cell of a row.
+ static std::string ParseElement(const std::string& line,
+ size_t* line_position,
+ int multi_value_length) {
+ std::string parsed_cell;
+ parsed_cell = "";
+ for (int i = 0; i < multi_value_length; ++i) {
+ size_t next_separator = line.find(',', *line_position);
+ EXPECT_NE(next_separator, std::string::npos);
+ if (next_separator == std::string::npos)
+ break;
+ parsed_cell += line.substr(*line_position,
+ next_separator - *line_position + 1);
+ *line_position = next_separator + 1;
+ }
+ return parsed_cell;
+ }
+
+ // This constant defines the maximum line length the DataLogParser can
+ // parse.
+ enum { kMaxLineLength = 100 };
+};
+
+TEST(TestDataLog, CreateReturnTest) {
+ for (int i = 0; i < 10; ++i)
+ ASSERT_EQ(DataLog::CreateLog(), 0);
+ ASSERT_EQ(DataLog::AddTable(DataLog::Combine("a proper table", 1)), 0);
+ for (int i = 0; i < 10; ++i)
+ DataLog::ReturnLog();
+ ASSERT_LT(DataLog::AddTable(DataLog::Combine("table failure", 1)), 0);
+}
+
+TEST(TestDataLog, VerifyCombineMethod) {
+ EXPECT_EQ(std::string("a proper table_1"),
+ DataLog::Combine("a proper table", 1));
+}
+
+TEST(TestDataLog, VerifySingleTable) {
+ DataLog::CreateLog();
+ DataLog::AddTable(DataLog::Combine("table", 1));
+ DataLog::AddColumn(DataLog::Combine("table", 1), "arrival", 1);
+ DataLog::AddColumn(DataLog::Combine("table", 1), "timestamp", 1);
+ DataLog::AddColumn(DataLog::Combine("table", 1), "size", 5);
+ uint32_t sizes[5] = {1400, 1500, 1600, 1700, 1800};
+ for (int i = 0; i < 10; ++i) {
+ DataLog::InsertCell(DataLog::Combine("table", 1), "arrival",
+ static_cast<double>(i));
+ DataLog::InsertCell(DataLog::Combine("table", 1), "timestamp",
+ static_cast<int64_t>(4354 + i));
+ DataLog::InsertCell(DataLog::Combine("table", 1), "size", sizes, 5);
+ DataLog::NextRow(DataLog::Combine("table", 1));
+ }
+ DataLog::ReturnLog();
+ // Verify file
+ FILE* table = fopen("table_1.txt", "r");
+ ASSERT_FALSE(table == NULL);
+ // Read the column names and verify with the expected columns.
+ // Note that the columns are written to file in alphabetical order.
+ // Data expected from parsing the file
+ const int kNumberOfRows = 10;
+ std::string string_arrival[kNumberOfRows] = {
+ "0,", "1,", "2,", "3,", "4,",
+ "5,", "6,", "7,", "8,", "9,"
+ };
+ std::string string_timestamp[kNumberOfRows] = {
+ "4354,", "4355,", "4356,", "4357,",
+ "4358,", "4359,", "4360,", "4361,",
+ "4362,", "4363,"
+ };
+ std::string string_sizes = "1400,1500,1600,1700,1800,";
+ ExpectedValuesMap expected;
+ expected["arrival,"] = ExpectedValues(
+ std::vector<std::string>(string_arrival,
+ string_arrival +
+ kNumberOfRows),
+ 1);
+ expected["size[5],,,,,"] = ExpectedValues(
+ std::vector<std::string>(10, string_sizes), 5);
+ expected["timestamp,"] = ExpectedValues(
+ std::vector<std::string>(string_timestamp,
+ string_timestamp +
+ kNumberOfRows),
+ 1);
+ ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
+ fclose(table);
+}
+
+TEST(TestDataLog, VerifyMultipleTables) {
+ DataLog::CreateLog();
+ DataLog::AddTable(DataLog::Combine("table", 2));
+ DataLog::AddTable(DataLog::Combine("table", 3));
+ DataLog::AddColumn(DataLog::Combine("table", 2), "arrival", 1);
+ DataLog::AddColumn(DataLog::Combine("table", 2), "timestamp", 1);
+ DataLog::AddColumn(DataLog::Combine("table", 2), "size", 1);
+ DataLog::AddTable(DataLog::Combine("table", 4));
+ DataLog::AddColumn(DataLog::Combine("table", 3), "timestamp", 1);
+ DataLog::AddColumn(DataLog::Combine("table", 3), "arrival", 1);
+ DataLog::AddColumn(DataLog::Combine("table", 4), "size", 1);
+ for (int32_t i = 0; i < 10; ++i) {
+ DataLog::InsertCell(DataLog::Combine("table", 2), "arrival",
+ static_cast<int32_t>(i));
+ DataLog::InsertCell(DataLog::Combine("table", 2), "timestamp",
+ static_cast<int32_t>(4354 + i));
+ DataLog::InsertCell(DataLog::Combine("table", 2), "size",
+ static_cast<int32_t>(1200 + 10 * i));
+ DataLog::InsertCell(DataLog::Combine("table", 3), "timestamp",
+ static_cast<int32_t>(4354 + i));
+ DataLog::InsertCell(DataLog::Combine("table", 3), "arrival",
+ static_cast<int32_t>(i));
+ DataLog::InsertCell(DataLog::Combine("table", 4), "size",
+ static_cast<int32_t>(1200 + 10 * i));
+ DataLog::NextRow(DataLog::Combine("table", 4));
+ DataLog::NextRow(DataLog::Combine("table", 2));
+ DataLog::NextRow(DataLog::Combine("table", 3));
+ }
+ DataLog::ReturnLog();
+
+ // Data expected from parsing the file
+ const int kNumberOfRows = 10;
+ std::string string_arrival[kNumberOfRows] = {
+ "0,", "1,", "2,", "3,", "4,",
+ "5,", "6,", "7,", "8,", "9,"
+ };
+ std::string string_timestamp[kNumberOfRows] = {
+ "4354,", "4355,", "4356,", "4357,",
+ "4358,", "4359,", "4360,", "4361,",
+ "4362,", "4363,"
+ };
+ std::string string_size[kNumberOfRows] = {
+ "1200,", "1210,", "1220,", "1230,",
+ "1240,", "1250,", "1260,", "1270,",
+ "1280,", "1290,"
+ };
+
+ // Verify table 2
+ {
+ FILE* table = fopen("table_2.txt", "r");
+ ASSERT_FALSE(table == NULL);
+ ExpectedValuesMap expected;
+ expected["arrival,"] = ExpectedValues(
+ std::vector<std::string>(string_arrival,
+ string_arrival +
+ kNumberOfRows),
+ 1);
+ expected["size,"] = ExpectedValues(
+ std::vector<std::string>(string_size,
+ string_size + kNumberOfRows),
+ 1);
+ expected["timestamp,"] = ExpectedValues(
+ std::vector<std::string>(string_timestamp,
+ string_timestamp +
+ kNumberOfRows),
+ 1);
+ ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
+ fclose(table);
+ }
+
+ // Verify table 3
+ {
+ FILE* table = fopen("table_3.txt", "r");
+ ASSERT_FALSE(table == NULL);
+ ExpectedValuesMap expected;
+ expected["arrival,"] = ExpectedValues(
+ std::vector<std::string>(string_arrival,
+ string_arrival +
+ kNumberOfRows),
+ 1);
+ expected["timestamp,"] = ExpectedValues(
+ std::vector<std::string>(string_timestamp,
+ string_timestamp +
+ kNumberOfRows),
+ 1);
+ ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
+ fclose(table);
+ }
+
+ // Verify table 4
+ {
+ FILE* table = fopen("table_4.txt", "r");
+ ASSERT_FALSE(table == NULL);
+ ExpectedValuesMap expected;
+ expected["size,"] = ExpectedValues(
+ std::vector<std::string>(string_size,
+ string_size +
+ kNumberOfRows),
+ 1);
+ ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
+ fclose(table);
+ }
+}
+
+TEST(TestDataLogCWrapper, VerifyCWrapper) {
+ // Simply call all C wrapper log functions through the C helper unittests.
+ // Main purpose is to make sure that the linkage is correct.
+
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestCreateLog());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestCombine());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestAddTable());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestAddColumn());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_float());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_float());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_double());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_double());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int32());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int32());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_uint32());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_uint32());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int64());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int64());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
+ EXPECT_EQ(0, WebRtcDataLogCHelper_TestReturnLog());
+}
diff --git a/webrtc/system_wrappers/source/data_log_unittest_disabled.cc b/webrtc/system_wrappers/source/data_log_unittest_disabled.cc
new file mode 100644
index 0000000000..1855a3e74f
--- /dev/null
+++ b/webrtc/system_wrappers/source/data_log_unittest_disabled.cc
@@ -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.
+ */
+
+#include "webrtc/system_wrappers/include/data_log.h"
+
+#include <stdio.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::webrtc::DataLog;
+
+const char* kDataLogFileName = "table_1.txt";
+
+void PerformLogging(const std::string& table_name) {
+ // Simulate normal DataTable logging behavior using this table name.
+ ASSERT_EQ(0, DataLog::AddTable(table_name));
+ ASSERT_EQ(0, DataLog::AddColumn(table_name, "test", 1));
+ for (int i = 0; i < 10; ++i) {
+ // TODO(kjellander): Check InsertCell result when the DataLog dummy is
+ // fixed.
+ DataLog::InsertCell(table_name, "test", static_cast<double>(i));
+ ASSERT_EQ(0, DataLog::NextRow(table_name));
+ }
+}
+
+// Simple test to verify DataLog is still working when the GYP variable
+// enable_data_logging==0 (the default case).
+TEST(TestDataLogDisabled, VerifyLoggingWorks) {
+ ASSERT_EQ(0, DataLog::CreateLog());
+ // Generate a table_name name and assure it's an empty string
+ // (dummy behavior).
+ std::string table_name = DataLog::Combine("table", 1);
+ ASSERT_EQ("", table_name);
+ PerformLogging(table_name);
+ DataLog::ReturnLog();
+}
+
+TEST(TestDataLogDisabled, EnsureNoFileIsWritten) {
+ // Remove any previous data files on disk:
+ remove(kDataLogFileName);
+ ASSERT_EQ(0, DataLog::CreateLog());
+ // Don't use the table name we would get from Combine on a disabled DataLog.
+ // Use "table_1" instead (which is what an enabled DataLog would give us).
+ PerformLogging("table_1");
+ DataLog::ReturnLog();
+ // Verify no data log file have been written:
+ ASSERT_EQ(NULL, fopen(kDataLogFileName, "r"));
+}
diff --git a/webrtc/system_wrappers/source/event.cc b/webrtc/system_wrappers/source/event.cc
new file mode 100644
index 0000000000..05f918ffc2
--- /dev/null
+++ b/webrtc/system_wrappers/source/event.cc
@@ -0,0 +1,54 @@
+/*
+ * 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 "webrtc/system_wrappers/include/event_wrapper.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+#include "webrtc/system_wrappers/source/event_timer_win.h"
+#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+#include <ApplicationServices/ApplicationServices.h>
+#include <pthread.h>
+#include "webrtc/system_wrappers/source/event_timer_posix.h"
+#else
+#include <pthread.h>
+#include "webrtc/system_wrappers/source/event_timer_posix.h"
+#endif
+
+#include "webrtc/base/event.h"
+
+namespace webrtc {
+
+class EventWrapperImpl : public EventWrapper {
+ public:
+ EventWrapperImpl() : event_(false, false) {}
+ ~EventWrapperImpl() override {}
+
+ bool Set() override {
+ event_.Set();
+ return true;
+ }
+
+ EventTypeWrapper Wait(unsigned long max_time) override {
+ int to_wait = max_time == WEBRTC_EVENT_INFINITE ?
+ rtc::Event::kForever : static_cast<int>(max_time);
+ return event_.Wait(to_wait) ? kEventSignaled : kEventTimeout;
+ }
+
+ private:
+ rtc::Event event_;
+};
+
+// static
+EventWrapper* EventWrapper::Create() {
+ return new EventWrapperImpl();
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/event_timer_posix.cc b/webrtc/system_wrappers/source/event_timer_posix.cc
new file mode 100644
index 0000000000..99eebcb70a
--- /dev/null
+++ b/webrtc/system_wrappers/source/event_timer_posix.cc
@@ -0,0 +1,231 @@
+/*
+ * 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 "webrtc/system_wrappers/source/event_timer_posix.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+// static
+EventTimerWrapper* EventTimerWrapper::Create() {
+ return new EventTimerPosix();
+}
+
+const long int E6 = 1000000;
+const long int E9 = 1000 * E6;
+
+EventTimerPosix::EventTimerPosix()
+ : event_set_(false),
+ timer_thread_(nullptr),
+ created_at_(),
+ periodic_(false),
+ time_(0),
+ count_(0) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mutex_, &attr);
+#ifdef WEBRTC_CLOCK_TYPE_REALTIME
+ pthread_cond_init(&cond_, 0);
+#else
+ pthread_condattr_t cond_attr;
+ pthread_condattr_init(&cond_attr);
+ pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
+ pthread_cond_init(&cond_, &cond_attr);
+ pthread_condattr_destroy(&cond_attr);
+#endif
+}
+
+EventTimerPosix::~EventTimerPosix() {
+ StopTimer();
+ pthread_cond_destroy(&cond_);
+ pthread_mutex_destroy(&mutex_);
+}
+
+// TODO(pbos): Make this void.
+bool EventTimerPosix::Set() {
+ RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
+ event_set_ = true;
+ pthread_cond_signal(&cond_);
+ pthread_mutex_unlock(&mutex_);
+ return true;
+}
+
+EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout) {
+ int ret_val = 0;
+ RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
+
+ if (!event_set_) {
+ if (WEBRTC_EVENT_INFINITE != timeout) {
+ timespec end_at;
+#ifndef WEBRTC_MAC
+#ifdef WEBRTC_CLOCK_TYPE_REALTIME
+ clock_gettime(CLOCK_REALTIME, &end_at);
+#else
+ clock_gettime(CLOCK_MONOTONIC, &end_at);
+#endif
+#else
+ timeval value;
+ struct timezone time_zone;
+ time_zone.tz_minuteswest = 0;
+ time_zone.tz_dsttime = 0;
+ gettimeofday(&value, &time_zone);
+ TIMEVAL_TO_TIMESPEC(&value, &end_at);
+#endif
+ end_at.tv_sec += timeout / 1000;
+ end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
+
+ if (end_at.tv_nsec >= E9) {
+ end_at.tv_sec++;
+ end_at.tv_nsec -= E9;
+ }
+ while (ret_val == 0 && !event_set_)
+ ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
+ } else {
+ while (ret_val == 0 && !event_set_)
+ ret_val = pthread_cond_wait(&cond_, &mutex_);
+ }
+ }
+
+ RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
+
+ // Reset and signal if set, regardless of why the thread woke up.
+ if (event_set_) {
+ ret_val = 0;
+ event_set_ = false;
+ }
+ pthread_mutex_unlock(&mutex_);
+
+ return ret_val == 0 ? kEventSignaled : kEventTimeout;
+}
+
+EventTypeWrapper EventTimerPosix::Wait(timespec* end_at) {
+ int ret_val = 0;
+ RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
+
+ while (ret_val == 0 && !event_set_)
+ ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at);
+
+ RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
+
+ // Reset and signal if set, regardless of why the thread woke up.
+ if (event_set_) {
+ ret_val = 0;
+ event_set_ = false;
+ }
+ pthread_mutex_unlock(&mutex_);
+
+ return ret_val == 0 ? kEventSignaled : kEventTimeout;
+}
+
+bool EventTimerPosix::StartTimer(bool periodic, unsigned long time) {
+ pthread_mutex_lock(&mutex_);
+ if (timer_thread_) {
+ if (periodic_) {
+ // Timer already started.
+ pthread_mutex_unlock(&mutex_);
+ return false;
+ } else {
+ // New one shot timer
+ time_ = time;
+ created_at_.tv_sec = 0;
+ timer_event_->Set();
+ pthread_mutex_unlock(&mutex_);
+ return true;
+ }
+ }
+
+ // Start the timer thread
+ timer_event_.reset(new EventTimerPosix());
+ const char* thread_name = "WebRtc_event_timer_thread";
+ timer_thread_ = ThreadWrapper::CreateThread(Run, this, thread_name);
+ periodic_ = periodic;
+ time_ = time;
+ bool started = timer_thread_->Start();
+ timer_thread_->SetPriority(kRealtimePriority);
+ pthread_mutex_unlock(&mutex_);
+
+ return started;
+}
+
+bool EventTimerPosix::Run(void* obj) {
+ return static_cast<EventTimerPosix*>(obj)->Process();
+}
+
+bool EventTimerPosix::Process() {
+ pthread_mutex_lock(&mutex_);
+ if (created_at_.tv_sec == 0) {
+#ifndef WEBRTC_MAC
+#ifdef WEBRTC_CLOCK_TYPE_REALTIME
+ clock_gettime(CLOCK_REALTIME, &created_at_);
+#else
+ clock_gettime(CLOCK_MONOTONIC, &created_at_);
+#endif
+#else
+ timeval value;
+ struct timezone time_zone;
+ time_zone.tz_minuteswest = 0;
+ time_zone.tz_dsttime = 0;
+ gettimeofday(&value, &time_zone);
+ TIMEVAL_TO_TIMESPEC(&value, &created_at_);
+#endif
+ count_ = 0;
+ }
+
+ timespec end_at;
+ unsigned long long time = time_ * ++count_;
+ end_at.tv_sec = created_at_.tv_sec + time / 1000;
+ end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
+
+ if (end_at.tv_nsec >= E9) {
+ end_at.tv_sec++;
+ end_at.tv_nsec -= E9;
+ }
+
+ pthread_mutex_unlock(&mutex_);
+ if (timer_event_->Wait(&end_at) == kEventSignaled)
+ return true;
+
+ pthread_mutex_lock(&mutex_);
+ if (periodic_ || count_ == 1)
+ Set();
+ pthread_mutex_unlock(&mutex_);
+
+ return true;
+}
+
+bool EventTimerPosix::StopTimer() {
+ if (timer_event_) {
+ timer_event_->Set();
+ }
+ if (timer_thread_) {
+ if (!timer_thread_->Stop()) {
+ return false;
+ }
+ timer_thread_.reset();
+ }
+ timer_event_.reset();
+
+ // Set time to zero to force new reference time for the timer.
+ memset(&created_at_, 0, sizeof(created_at_));
+ count_ = 0;
+ return true;
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/event_timer_posix.h b/webrtc/system_wrappers/source/event_timer_posix.h
new file mode 100644
index 0000000000..21c4ac702e
--- /dev/null
+++ b/webrtc/system_wrappers/source/event_timer_posix.h
@@ -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.
+ */
+
+#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
+
+#include "webrtc/system_wrappers/include/event_wrapper.h"
+
+#include <pthread.h>
+#include <time.h>
+
+#include "webrtc/system_wrappers/include/thread_wrapper.h"
+
+namespace webrtc {
+
+enum State {
+ kUp = 1,
+ kDown = 2
+};
+
+class EventTimerPosix : public EventTimerWrapper {
+ public:
+ EventTimerPosix();
+ ~EventTimerPosix() override;
+
+ EventTypeWrapper Wait(unsigned long max_time) override;
+ bool Set() override;
+
+ bool StartTimer(bool periodic, unsigned long time) override;
+ bool StopTimer() override;
+
+ private:
+ static bool Run(void* obj);
+ bool Process();
+ EventTypeWrapper Wait(timespec* end_at);
+
+ private:
+ pthread_cond_t cond_;
+ pthread_mutex_t mutex_;
+ bool event_set_;
+
+ rtc::scoped_ptr<ThreadWrapper> timer_thread_;
+ rtc::scoped_ptr<EventTimerPosix> timer_event_;
+ timespec created_at_;
+
+ bool periodic_;
+ unsigned long time_; // In ms
+ unsigned long count_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
diff --git a/webrtc/system_wrappers/source/event_timer_win.cc b/webrtc/system_wrappers/source/event_timer_win.cc
new file mode 100644
index 0000000000..4c586988df
--- /dev/null
+++ b/webrtc/system_wrappers/source/event_timer_win.cc
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/event_timer_win.h"
+
+#include "Mmsystem.h"
+
+namespace webrtc {
+
+// static
+EventTimerWrapper* EventTimerWrapper::Create() {
+ return new EventTimerWin();
+}
+
+EventTimerWin::EventTimerWin()
+ : event_(::CreateEvent(NULL, // security attributes
+ FALSE, // manual reset
+ FALSE, // initial state
+ NULL)), // name of event
+ timerID_(NULL) {
+}
+
+EventTimerWin::~EventTimerWin() {
+ StopTimer();
+ CloseHandle(event_);
+}
+
+bool EventTimerWin::Set() {
+ // Note: setting an event that is already set has no effect.
+ return SetEvent(event_) == 1;
+}
+
+EventTypeWrapper EventTimerWin::Wait(unsigned long max_time) {
+ unsigned long res = WaitForSingleObject(event_, max_time);
+ switch (res) {
+ case WAIT_OBJECT_0:
+ return kEventSignaled;
+ case WAIT_TIMEOUT:
+ return kEventTimeout;
+ default:
+ return kEventError;
+ }
+}
+
+bool EventTimerWin::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);
+ }
+
+ return timerID_ != NULL;
+}
+
+bool EventTimerWin::StopTimer() {
+ if (timerID_ != NULL) {
+ timeKillEvent(timerID_);
+ timerID_ = NULL;
+ }
+
+ return true;
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/event_timer_win.h b/webrtc/system_wrappers/source/event_timer_win.h
new file mode 100644
index 0000000000..163cddeda9
--- /dev/null
+++ b/webrtc/system_wrappers/source/event_timer_win.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_WIN_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
+
+#include <windows.h>
+
+#include "webrtc/system_wrappers/include/event_wrapper.h"
+
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+class EventTimerWin : public EventTimerWrapper {
+ public:
+ EventTimerWin();
+ virtual ~EventTimerWin();
+
+ virtual EventTypeWrapper Wait(unsigned long max_time);
+ virtual bool Set();
+
+ virtual bool StartTimer(bool periodic, unsigned long time);
+ virtual bool StopTimer();
+
+ private:
+ HANDLE event_;
+ uint32_t timerID_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
diff --git a/webrtc/system_wrappers/source/event_tracer.cc b/webrtc/system_wrappers/source/event_tracer.cc
new file mode 100644
index 0000000000..9328e80036
--- /dev/null
+++ b/webrtc/system_wrappers/source/event_tracer.cc
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+// This file has moved.
+// TODO(tommi): Delete after removing dependencies and updating Chromium.
diff --git a/webrtc/system_wrappers/source/event_tracer_unittest.cc b/webrtc/system_wrappers/source/event_tracer_unittest.cc
new file mode 100644
index 0000000000..9328e80036
--- /dev/null
+++ b/webrtc/system_wrappers/source/event_tracer_unittest.cc
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+
+// This file has moved.
+// TODO(tommi): Delete after removing dependencies and updating Chromium.
diff --git a/webrtc/system_wrappers/source/field_trial_default.cc b/webrtc/system_wrappers/source/field_trial_default.cc
new file mode 100644
index 0000000000..1a9bd6bc79
--- /dev/null
+++ b/webrtc/system_wrappers/source/field_trial_default.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2014 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 "webrtc/system_wrappers/include/field_trial.h"
+#include "webrtc/system_wrappers/include/field_trial_default.h"
+
+#include <string>
+
+// Simple field trial implementation, which allows client to
+// specify desired flags in InitFieldTrialsFromString.
+namespace webrtc {
+namespace field_trial {
+
+static const char *trials_init_string = NULL;
+
+std::string FindFullName(const std::string& name) {
+ if (trials_init_string == NULL)
+ return std::string();
+
+ std::string trials_string(trials_init_string);
+ if (trials_string.empty())
+ return std::string();
+
+ static const char kPersistentStringSeparator = '/';
+ size_t next_item = 0;
+ while (next_item < trials_string.length()) {
+
+ // Find next name/value pair in field trial configuration string.
+ size_t field_name_end = trials_string.find(
+ kPersistentStringSeparator, next_item);
+ if (field_name_end == trials_string.npos || field_name_end == next_item)
+ break;
+ size_t field_value_end = trials_string.find(
+ kPersistentStringSeparator, field_name_end + 1);
+ if (field_value_end == trials_string.npos ||
+ field_value_end == field_name_end + 1)
+ break;
+ std::string field_name(trials_string, next_item,
+ field_name_end - next_item);
+ std::string field_value(trials_string, field_name_end + 1,
+ field_value_end - field_name_end - 1);
+ next_item = field_value_end + 1;
+
+ if (name == field_name)
+ return field_value;
+ }
+ return std::string();
+}
+
+// Optionally initialize field trial from a string.
+void InitFieldTrialsFromString(const char* trials_string) {
+ trials_init_string = trials_string;
+}
+
+} // namespace field_trial
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/file_impl.cc b/webrtc/system_wrappers/source/file_impl.cc
new file mode 100644
index 0000000000..0ee0deab6c
--- /dev/null
+++ b/webrtc/system_wrappers/source/file_impl.cc
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/file_impl.h"
+
+#include <assert.h>
+
+#ifdef _WIN32
+#include <Windows.h>
+#else
+#include <stdarg.h>
+#include <string.h>
+#endif
+
+#include "webrtc/base/checks.h"
+#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+
+namespace webrtc {
+
+FileWrapper* FileWrapper::Create() {
+ return new FileWrapperImpl();
+}
+
+FileWrapperImpl::FileWrapperImpl()
+ : rw_lock_(RWLockWrapper::CreateRWLock()),
+ id_(NULL),
+ managed_file_handle_(true),
+ open_(false),
+ looping_(false),
+ read_only_(false),
+ max_size_in_bytes_(0),
+ size_in_bytes_(0) {
+ memset(file_name_utf8_, 0, kMaxFileNameSize);
+}
+
+FileWrapperImpl::~FileWrapperImpl() {
+ if (id_ != NULL && managed_file_handle_) {
+ fclose(id_);
+ }
+}
+
+int FileWrapperImpl::CloseFile() {
+ WriteLockScoped write(*rw_lock_);
+ return CloseFileImpl();
+}
+
+int FileWrapperImpl::Rewind() {
+ WriteLockScoped write(*rw_lock_);
+ if (looping_ || !read_only_) {
+ if (id_ != NULL) {
+ size_in_bytes_ = 0;
+ return fseek(id_, 0, SEEK_SET);
+ }
+ }
+ return -1;
+}
+
+int FileWrapperImpl::SetMaxFileSize(size_t bytes) {
+ WriteLockScoped write(*rw_lock_);
+ max_size_in_bytes_ = bytes;
+ return 0;
+}
+
+int FileWrapperImpl::Flush() {
+ WriteLockScoped write(*rw_lock_);
+ return FlushImpl();
+}
+
+int FileWrapperImpl::FileName(char* file_name_utf8, size_t size) const {
+ ReadLockScoped read(*rw_lock_);
+ size_t length = strlen(file_name_utf8_);
+ if (length > kMaxFileNameSize) {
+ assert(false);
+ return -1;
+ }
+ if (length < 1) {
+ return -1;
+ }
+
+ // Make sure to NULL terminate
+ if (size < length) {
+ length = size - 1;
+ }
+ memcpy(file_name_utf8, file_name_utf8_, length);
+ file_name_utf8[length] = 0;
+ return 0;
+}
+
+bool FileWrapperImpl::Open() const {
+ ReadLockScoped read(*rw_lock_);
+ return open_;
+}
+
+int FileWrapperImpl::OpenFile(const char* file_name_utf8, bool read_only,
+ bool loop, bool text) {
+ WriteLockScoped write(*rw_lock_);
+ if (id_ != NULL && !managed_file_handle_)
+ return -1;
+ size_t length = strlen(file_name_utf8);
+ if (length > kMaxFileNameSize - 1) {
+ return -1;
+ }
+
+ read_only_ = read_only;
+
+ FILE* tmp_id = NULL;
+#if defined _WIN32
+ wchar_t wide_file_name[kMaxFileNameSize];
+ wide_file_name[0] = 0;
+
+ MultiByteToWideChar(CP_UTF8,
+ 0, // UTF8 flag
+ file_name_utf8,
+ -1, // Null terminated string
+ wide_file_name,
+ kMaxFileNameSize);
+ if (text) {
+ if (read_only) {
+ tmp_id = _wfopen(wide_file_name, L"rt");
+ } else {
+ tmp_id = _wfopen(wide_file_name, L"wt");
+ }
+ } else {
+ if (read_only) {
+ tmp_id = _wfopen(wide_file_name, L"rb");
+ } else {
+ tmp_id = _wfopen(wide_file_name, L"wb");
+ }
+ }
+#else
+ if (text) {
+ if (read_only) {
+ tmp_id = fopen(file_name_utf8, "rt");
+ } else {
+ tmp_id = fopen(file_name_utf8, "wt");
+ }
+ } else {
+ if (read_only) {
+ tmp_id = fopen(file_name_utf8, "rb");
+ } else {
+ tmp_id = fopen(file_name_utf8, "wb");
+ }
+ }
+#endif
+
+ if (tmp_id != NULL) {
+ // +1 comes from copying the NULL termination character.
+ memcpy(file_name_utf8_, file_name_utf8, length + 1);
+ if (id_ != NULL) {
+ fclose(id_);
+ }
+ id_ = tmp_id;
+ managed_file_handle_ = true;
+ looping_ = loop;
+ open_ = true;
+ return 0;
+ }
+ return -1;
+}
+
+int FileWrapperImpl::OpenFromFileHandle(FILE* handle,
+ bool manage_file,
+ bool read_only,
+ bool loop) {
+ WriteLockScoped write(*rw_lock_);
+ if (!handle)
+ return -1;
+
+ if (id_ != NULL) {
+ if (managed_file_handle_)
+ fclose(id_);
+ else
+ return -1;
+ }
+
+ id_ = handle;
+ managed_file_handle_ = manage_file;
+ read_only_ = read_only;
+ looping_ = loop;
+ open_ = true;
+ return 0;
+}
+
+int FileWrapperImpl::Read(void* buf, size_t length) {
+ WriteLockScoped write(*rw_lock_);
+ if (id_ == NULL)
+ return -1;
+
+ size_t bytes_read = fread(buf, 1, length, id_);
+ if (bytes_read != length && !looping_) {
+ CloseFileImpl();
+ }
+ return static_cast<int>(bytes_read);
+}
+
+int FileWrapperImpl::WriteText(const char* format, ...) {
+ WriteLockScoped write(*rw_lock_);
+ if (format == NULL)
+ return -1;
+
+ if (read_only_)
+ return -1;
+
+ if (id_ == NULL)
+ return -1;
+
+ va_list args;
+ va_start(args, format);
+ int num_chars = vfprintf(id_, format, args);
+ va_end(args);
+
+ if (num_chars >= 0) {
+ return num_chars;
+ } else {
+ CloseFileImpl();
+ return -1;
+ }
+}
+
+bool FileWrapperImpl::Write(const void* buf, size_t length) {
+ WriteLockScoped write(*rw_lock_);
+ if (buf == NULL)
+ return false;
+
+ if (read_only_)
+ return false;
+
+ if (id_ == NULL)
+ return false;
+
+ // Check if it's time to stop writing.
+ if (max_size_in_bytes_ > 0 &&
+ (size_in_bytes_ + length) > max_size_in_bytes_) {
+ FlushImpl();
+ return false;
+ }
+
+ size_t num_bytes = fwrite(buf, 1, length, id_);
+ if (num_bytes > 0) {
+ size_in_bytes_ += num_bytes;
+ return true;
+ }
+
+ CloseFileImpl();
+ return false;
+}
+
+int FileWrapperImpl::CloseFileImpl() {
+ if (id_ != NULL) {
+ if (managed_file_handle_)
+ fclose(id_);
+ id_ = NULL;
+ }
+ memset(file_name_utf8_, 0, kMaxFileNameSize);
+ open_ = false;
+ return 0;
+}
+
+int FileWrapperImpl::FlushImpl() {
+ if (id_ != NULL) {
+ return fflush(id_);
+ }
+ return -1;
+}
+
+int FileWrapper::Rewind() {
+ RTC_DCHECK(false);
+ return -1;
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/file_impl.h b/webrtc/system_wrappers/source/file_impl.h
new file mode 100644
index 0000000000..06ba58200b
--- /dev/null
+++ b/webrtc/system_wrappers/source/file_impl.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_FILE_IMPL_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_
+
+#include <stdio.h>
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/file_wrapper.h"
+
+namespace webrtc {
+
+class RWLockWrapper;
+
+class FileWrapperImpl : public FileWrapper {
+ public:
+ FileWrapperImpl();
+ ~FileWrapperImpl() override;
+
+ int FileName(char* file_name_utf8, size_t size) const override;
+
+ bool Open() const override;
+
+ int OpenFile(const char* file_name_utf8,
+ bool read_only,
+ bool loop = false,
+ bool text = false) override;
+
+ int OpenFromFileHandle(FILE* handle,
+ bool manage_file,
+ bool read_only,
+ bool loop = false) override;
+
+ int CloseFile() override;
+ int SetMaxFileSize(size_t bytes) override;
+ int Flush() override;
+
+ int Read(void* buf, size_t length) override;
+ bool Write(const void* buf, size_t length) override;
+ int WriteText(const char* format, ...) override;
+ int Rewind() override;
+
+ private:
+ int CloseFileImpl();
+ int FlushImpl();
+
+ rtc::scoped_ptr<RWLockWrapper> rw_lock_;
+
+ FILE* id_;
+ bool managed_file_handle_;
+ bool open_;
+ bool looping_;
+ bool read_only_;
+ size_t max_size_in_bytes_; // -1 indicates file size limitation is off
+ size_t size_in_bytes_;
+ char file_name_utf8_[kMaxFileNameSize];
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_
diff --git a/webrtc/system_wrappers/source/logcat_trace_context.cc b/webrtc/system_wrappers/source/logcat_trace_context.cc
new file mode 100644
index 0000000000..cc2e45b28e
--- /dev/null
+++ b/webrtc/system_wrappers/source/logcat_trace_context.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013 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 "webrtc/system_wrappers/include/logcat_trace_context.h"
+
+#include <android/log.h>
+#include <assert.h>
+
+#include "webrtc/system_wrappers/include/logging.h"
+
+namespace webrtc {
+
+static android_LogPriority AndroidLogPriorityFromWebRtcLogLevel(
+ TraceLevel webrtc_level) {
+ // NOTE: this mapping is somewhat arbitrary. StateInfo and Info are mapped
+ // to DEBUG because they are highly verbose in webrtc code (which is
+ // unfortunate).
+ switch (webrtc_level) {
+ case webrtc::kTraceStateInfo: return ANDROID_LOG_DEBUG;
+ case webrtc::kTraceWarning: return ANDROID_LOG_WARN;
+ case webrtc::kTraceError: return ANDROID_LOG_ERROR;
+ case webrtc::kTraceCritical: return ANDROID_LOG_FATAL;
+ case webrtc::kTraceApiCall: return ANDROID_LOG_VERBOSE;
+ case webrtc::kTraceModuleCall: return ANDROID_LOG_VERBOSE;
+ case webrtc::kTraceMemory: return ANDROID_LOG_VERBOSE;
+ case webrtc::kTraceTimer: return ANDROID_LOG_VERBOSE;
+ case webrtc::kTraceStream: return ANDROID_LOG_VERBOSE;
+ case webrtc::kTraceDebug: return ANDROID_LOG_DEBUG;
+ case webrtc::kTraceInfo: return ANDROID_LOG_DEBUG;
+ case webrtc::kTraceTerseInfo: return ANDROID_LOG_INFO;
+ default:
+ LOG(LS_ERROR) << "Unexpected log level" << webrtc_level;
+ return ANDROID_LOG_FATAL;
+ }
+}
+
+LogcatTraceContext::LogcatTraceContext() {
+ webrtc::Trace::CreateTrace();
+ if (webrtc::Trace::SetTraceCallback(this) != 0)
+ assert(false);
+}
+
+LogcatTraceContext::~LogcatTraceContext() {
+ if (webrtc::Trace::SetTraceCallback(NULL) != 0)
+ assert(false);
+ webrtc::Trace::ReturnTrace();
+}
+
+void LogcatTraceContext::Print(TraceLevel level,
+ const char* message,
+ int length) {
+ __android_log_print(AndroidLogPriorityFromWebRtcLogLevel(level),
+ "WEBRTC", "%.*s", length, message);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/logging.cc b/webrtc/system_wrappers/source/logging.cc
new file mode 100644
index 0000000000..6b50d6acf8
--- /dev/null
+++ b/webrtc/system_wrappers/source/logging.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/logging.h"
+
+#include <string.h>
+
+#include <sstream>
+
+#include "webrtc/common_types.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+namespace {
+
+TraceLevel WebRtcSeverity(LoggingSeverity sev) {
+ switch (sev) {
+ // TODO(ajm): SENSITIVE doesn't have a corresponding webrtc level.
+ case LS_SENSITIVE: return kTraceInfo;
+ case LS_VERBOSE: return kTraceInfo;
+ case LS_INFO: return kTraceTerseInfo;
+ case LS_WARNING: return kTraceWarning;
+ case LS_ERROR: return kTraceError;
+ default: return kTraceNone;
+ }
+}
+
+// Return the filename portion of the string (that following the last slash).
+const char* FilenameFromPath(const char* file) {
+ const char* end1 = ::strrchr(file, '/');
+ const char* end2 = ::strrchr(file, '\\');
+ if (!end1 && !end2)
+ return file;
+ else
+ return (end1 > end2) ? end1 + 1 : end2 + 1;
+}
+
+} // namespace
+
+LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
+ : severity_(sev) {
+ print_stream_ << "(" << FilenameFromPath(file) << ":" << line << "): ";
+}
+
+bool LogMessage::Loggable(LoggingSeverity sev) {
+ // |level_filter| is a bitmask, unlike libjingle's minimum severity value.
+ return WebRtcSeverity(sev) & Trace::level_filter() ? true : false;
+}
+
+LogMessage::~LogMessage() {
+ const std::string& str = print_stream_.str();
+ Trace::Add(WebRtcSeverity(severity_), kTraceUndefined, 0, "%s", str.c_str());
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/logging_unittest.cc b/webrtc/system_wrappers/source/logging_unittest.cc
new file mode 100644
index 0000000000..633d84b76b
--- /dev/null
+++ b/webrtc/system_wrappers/source/logging_unittest.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/logging.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/include/sleep.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+namespace {
+
+class LoggingTest : public ::testing::Test, public TraceCallback {
+ public:
+ virtual void Print(TraceLevel level, const char* msg, int length) {
+ CriticalSectionScoped cs(crit_.get());
+ // We test the length here to ensure (with high likelihood) that only our
+ // traces will be tested.
+ if (level_ != kTraceNone && static_cast<int>(expected_log_.str().size()) ==
+ length - Trace::kBoilerplateLength - 1) {
+ EXPECT_EQ(level_, level);
+ EXPECT_EQ(expected_log_.str(), &msg[Trace::kBoilerplateLength]);
+ level_ = kTraceNone;
+ cv_->Wake();
+ }
+ }
+
+ protected:
+ LoggingTest()
+ : crit_(CriticalSectionWrapper::CreateCriticalSection()),
+ cv_(ConditionVariableWrapper::CreateConditionVariable()),
+ level_(kTraceNone),
+ expected_log_() {
+ }
+
+ void SetUp() {
+ Trace::CreateTrace();
+ Trace::SetTraceCallback(this);
+ }
+
+ void TearDown() {
+ Trace::SetTraceCallback(NULL);
+ Trace::ReturnTrace();
+ CriticalSectionScoped cs(crit_.get());
+ ASSERT_EQ(kTraceNone, level_) << "Print() was not called";
+ }
+
+ rtc::scoped_ptr<CriticalSectionWrapper> crit_;
+ rtc::scoped_ptr<ConditionVariableWrapper> cv_;
+ TraceLevel level_ GUARDED_BY(crit_);
+ std::ostringstream expected_log_ GUARDED_BY(crit_);
+};
+
+TEST_F(LoggingTest, LogStream) {
+ {
+ CriticalSectionScoped cs(crit_.get());
+ level_ = kTraceWarning;
+ std::string msg = "Important message";
+ expected_log_ << "(logging_unittest.cc:" << __LINE__ + 1 << "): " << msg;
+ LOG(LS_WARNING) << msg;
+ cv_->SleepCS(*crit_.get(), 2000);
+ }
+}
+
+TEST_F(LoggingTest, LogFunctionError) {
+ {
+ CriticalSectionScoped cs(crit_.get());
+ int bar = 42;
+ int baz = 99;
+ level_ = kTraceError;
+ expected_log_ << "(logging_unittest.cc:" << __LINE__ + 2
+ << "): Foo failed: bar=" << bar << ", baz=" << baz;
+ LOG_FERR2(LS_ERROR, Foo, bar, baz);
+ cv_->SleepCS(*crit_.get(), 2000);
+ }
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/metrics_default.cc b/webrtc/system_wrappers/source/metrics_default.cc
new file mode 100644
index 0000000000..48c9111e1b
--- /dev/null
+++ b/webrtc/system_wrappers/source/metrics_default.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2014 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 "webrtc/system_wrappers/include/metrics.h"
+
+// Default implementation of histogram methods for WebRTC clients that do not
+// want to provide their own implementation.
+
+namespace webrtc {
+namespace metrics {
+
+Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max,
+ int bucket_count) { return NULL; }
+
+Histogram* HistogramFactoryGetEnumeration(const std::string& name,
+ int boundary) { return NULL; }
+
+void HistogramAdd(
+ Histogram* histogram_pointer, const std::string& name, int sample) {}
+
+} // namespace metrics
+} // namespace webrtc
+
diff --git a/webrtc/system_wrappers/source/rtp_to_ntp.cc b/webrtc/system_wrappers/source/rtp_to_ntp.cc
new file mode 100644
index 0000000000..0aceb0625f
--- /dev/null
+++ b/webrtc/system_wrappers/source/rtp_to_ntp.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/rtp_to_ntp.h"
+
+#include "webrtc/system_wrappers/include/clock.h"
+
+#include <assert.h>
+
+namespace webrtc {
+
+RtcpMeasurement::RtcpMeasurement()
+ : ntp_secs(0), ntp_frac(0), rtp_timestamp(0) {}
+
+RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac,
+ uint32_t timestamp)
+ : ntp_secs(ntp_secs), ntp_frac(ntp_frac), rtp_timestamp(timestamp) {}
+
+// Calculates the RTP timestamp frequency from two pairs of NTP and RTP
+// timestamps.
+bool CalculateFrequency(
+ int64_t rtcp_ntp_ms1,
+ uint32_t rtp_timestamp1,
+ int64_t rtcp_ntp_ms2,
+ uint32_t rtp_timestamp2,
+ double* frequency_khz) {
+ if (rtcp_ntp_ms1 <= rtcp_ntp_ms2) {
+ return false;
+ }
+ *frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) /
+ static_cast<double>(rtcp_ntp_ms1 - rtcp_ntp_ms2);
+ return true;
+}
+
+// Detects if there has been a wraparound between |old_timestamp| and
+// |new_timestamp|, and compensates by adding 2^32 if that is the case.
+bool CompensateForWrapAround(uint32_t new_timestamp,
+ uint32_t old_timestamp,
+ int64_t* compensated_timestamp) {
+ assert(compensated_timestamp);
+ int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp);
+ if (wraps < 0) {
+ // Reordering, don't use this packet.
+ return false;
+ }
+ *compensated_timestamp = new_timestamp + (wraps << 32);
+ return true;
+}
+
+bool UpdateRtcpList(uint32_t ntp_secs,
+ uint32_t ntp_frac,
+ uint32_t rtp_timestamp,
+ RtcpList* rtcp_list,
+ bool* new_rtcp_sr) {
+ *new_rtcp_sr = false;
+ if (ntp_secs == 0 && ntp_frac == 0) {
+ return false;
+ }
+
+ RtcpMeasurement measurement;
+ measurement.ntp_secs = ntp_secs;
+ measurement.ntp_frac = ntp_frac;
+ measurement.rtp_timestamp = rtp_timestamp;
+
+ for (RtcpList::iterator it = rtcp_list->begin();
+ it != rtcp_list->end(); ++it) {
+ if (measurement.ntp_secs == (*it).ntp_secs &&
+ measurement.ntp_frac == (*it).ntp_frac) {
+ // This RTCP has already been added to the list.
+ return true;
+ }
+ }
+
+ // We need two RTCP SR reports to map between RTP and NTP. More than two will
+ // not improve the mapping.
+ if (rtcp_list->size() == 2) {
+ rtcp_list->pop_back();
+ }
+ rtcp_list->push_front(measurement);
+ *new_rtcp_sr = true;
+ return true;
+}
+
+// Converts |rtp_timestamp| to the NTP time base using the NTP and RTP timestamp
+// pairs in |rtcp|. The converted timestamp is returned in
+// |rtp_timestamp_in_ms|. This function compensates for wrap arounds in RTP
+// timestamps and returns false if it can't do the conversion due to reordering.
+bool RtpToNtpMs(int64_t rtp_timestamp,
+ const RtcpList& rtcp,
+ int64_t* rtp_timestamp_in_ms) {
+ assert(rtcp.size() == 2);
+ int64_t rtcp_ntp_ms_new = Clock::NtpToMs(rtcp.front().ntp_secs,
+ rtcp.front().ntp_frac);
+ int64_t rtcp_ntp_ms_old = Clock::NtpToMs(rtcp.back().ntp_secs,
+ rtcp.back().ntp_frac);
+ int64_t rtcp_timestamp_new = rtcp.front().rtp_timestamp;
+ int64_t rtcp_timestamp_old = rtcp.back().rtp_timestamp;
+ if (!CompensateForWrapAround(rtcp_timestamp_new,
+ rtcp_timestamp_old,
+ &rtcp_timestamp_new)) {
+ return false;
+ }
+ double freq_khz;
+ if (!CalculateFrequency(rtcp_ntp_ms_new,
+ rtcp_timestamp_new,
+ rtcp_ntp_ms_old,
+ rtcp_timestamp_old,
+ &freq_khz)) {
+ return false;
+ }
+ double offset = rtcp_timestamp_new - freq_khz * rtcp_ntp_ms_new;
+ int64_t rtp_timestamp_unwrapped;
+ if (!CompensateForWrapAround(rtp_timestamp, rtcp_timestamp_old,
+ &rtp_timestamp_unwrapped)) {
+ return false;
+ }
+ double rtp_timestamp_ntp_ms = (static_cast<double>(rtp_timestamp_unwrapped) -
+ offset) / freq_khz + 0.5f;
+ if (rtp_timestamp_ntp_ms < 0) {
+ return false;
+ }
+ *rtp_timestamp_in_ms = rtp_timestamp_ntp_ms;
+ return true;
+}
+
+int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) {
+ if (new_timestamp < old_timestamp) {
+ // This difference should be less than -2^31 if we have had a wrap around
+ // (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is
+ // cast to a int32_t, it should be positive.
+ if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) {
+ // Forward wrap around.
+ return 1;
+ }
+ } else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) {
+ // This difference should be less than -2^31 if we have had a backward wrap
+ // around. Since it is cast to a int32_t, it should be positive.
+ return -1;
+ }
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rtp_to_ntp_unittest.cc b/webrtc/system_wrappers/source/rtp_to_ntp_unittest.cc
new file mode 100644
index 0000000000..4c166774a4
--- /dev/null
+++ b/webrtc/system_wrappers/source/rtp_to_ntp_unittest.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2012 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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
+
+namespace webrtc {
+
+TEST(WrapAroundTests, NoWrap) {
+ EXPECT_EQ(0, CheckForWrapArounds(0xFFFFFFFF, 0xFFFFFFFE));
+ EXPECT_EQ(0, CheckForWrapArounds(1, 0));
+ EXPECT_EQ(0, CheckForWrapArounds(0x00010000, 0x0000FFFF));
+}
+
+TEST(WrapAroundTests, ForwardWrap) {
+ EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFFFFFF));
+ EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFF0000));
+ EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFFFFFF));
+ EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFF0000));
+}
+
+TEST(WrapAroundTests, BackwardWrap) {
+ EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0));
+ EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0));
+ EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0x0000FFFF));
+ EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0x0000FFFF));
+}
+
+TEST(WrapAroundTests, OldRtcpWrapped) {
+ RtcpList rtcp;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 0;
+ uint32_t timestamp = 0;
+ const uint32_t kOneMsInNtpFrac = 4294967;
+ const uint32_t kTimestampTicksPerMs = 90;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ int64_t timestamp_in_ms = -1;
+ // This expected to fail since it's highly unlikely that the older RTCP
+ // has a much smaller RTP timestamp than the newer.
+ EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
+}
+
+TEST(WrapAroundTests, NewRtcpWrapped) {
+ RtcpList rtcp;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 0;
+ uint32_t timestamp = 0xFFFFFFFF;
+ const uint32_t kOneMsInNtpFrac = 4294967;
+ const uint32_t kTimestampTicksPerMs = 90;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ int64_t timestamp_in_ms = -1;
+ EXPECT_TRUE(RtpToNtpMs(rtcp.back().rtp_timestamp, rtcp, &timestamp_in_ms));
+ // Since this RTP packet has the same timestamp as the RTCP packet constructed
+ // at time 0 it should be mapped to 0 as well.
+ EXPECT_EQ(0, timestamp_in_ms);
+}
+
+TEST(WrapAroundTests, RtpWrapped) {
+ const uint32_t kOneMsInNtpFrac = 4294967;
+ const uint32_t kTimestampTicksPerMs = 90;
+ RtcpList rtcp;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 0;
+ uint32_t timestamp = 0xFFFFFFFF - 2 * kTimestampTicksPerMs;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ int64_t timestamp_in_ms = -1;
+ EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
+ // Since this RTP packet has the same timestamp as the RTCP packet constructed
+ // at time 0 it should be mapped to 0 as well.
+ EXPECT_EQ(2, timestamp_in_ms);
+}
+
+TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
+ const uint32_t kOneMsInNtpFrac = 4294967;
+ const uint32_t kTimestampTicksPerMs = 90;
+ RtcpList rtcp;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 0;
+ uint32_t timestamp = 0;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= 2*kTimestampTicksPerMs;
+ int64_t timestamp_in_ms = -1;
+ EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
+}
+
+TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
+ const uint32_t kOneMsInNtpFrac = 4294967;
+ const uint32_t kTimestampTicksPerMs = 90;
+ RtcpList rtcp;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 0;
+ uint32_t timestamp = 0xFFFFFFFF;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += kTimestampTicksPerMs;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ int64_t timestamp_in_ms = -1;
+ EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
+ // Constructed at the same time as the first RTCP and should therefore be
+ // mapped to zero.
+ EXPECT_EQ(0, timestamp_in_ms);
+}
+
+TEST(WrapAroundTests, OldRtp_OldRtcpWrapped) {
+ const uint32_t kOneMsInNtpFrac = 4294967;
+ const uint32_t kTimestampTicksPerMs = 90;
+ RtcpList rtcp;
+ uint32_t ntp_sec = 0;
+ uint32_t ntp_frac = 0;
+ uint32_t timestamp = 0;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp -= kTimestampTicksPerMs;
+ rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
+ ntp_frac += kOneMsInNtpFrac;
+ timestamp += 2*kTimestampTicksPerMs;
+ int64_t timestamp_in_ms = -1;
+ EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
+}
+}; // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rw_lock.cc b/webrtc/system_wrappers/source/rw_lock.cc
new file mode 100644
index 0000000000..ff44896dbe
--- /dev/null
+++ b/webrtc/system_wrappers/source/rw_lock.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+
+#include <assert.h>
+
+#if defined(_WIN32)
+#include "webrtc/system_wrappers/source/rw_lock_generic.h"
+#include "webrtc/system_wrappers/source/rw_lock_win.h"
+#else
+#include "webrtc/system_wrappers/source/rw_lock_posix.h"
+#endif
+
+namespace webrtc {
+
+RWLockWrapper* RWLockWrapper::CreateRWLock() {
+#ifdef _WIN32
+ // Native implementation is faster, so use that if available.
+ RWLockWrapper* lock = RWLockWin::Create();
+ if (lock) {
+ return lock;
+ }
+ return new RWLockGeneric();
+#else
+ return RWLockPosix::Create();
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rw_lock_generic.cc b/webrtc/system_wrappers/source/rw_lock_generic.cc
new file mode 100644
index 0000000000..9786155a63
--- /dev/null
+++ b/webrtc/system_wrappers/source/rw_lock_generic.cc
@@ -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.
+ */
+
+#include "webrtc/system_wrappers/source/rw_lock_generic.h"
+
+#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+
+namespace webrtc {
+
+RWLockGeneric::RWLockGeneric()
+ : readers_active_(0),
+ writer_active_(false),
+ readers_waiting_(0),
+ writers_waiting_(0) {
+ critical_section_ = CriticalSectionWrapper::CreateCriticalSection();
+ read_condition_ = ConditionVariableWrapper::CreateConditionVariable();
+ write_condition_ = ConditionVariableWrapper::CreateConditionVariable();
+}
+
+RWLockGeneric::~RWLockGeneric() {
+ delete write_condition_;
+ delete read_condition_;
+ delete critical_section_;
+}
+
+void RWLockGeneric::AcquireLockExclusive() {
+ CriticalSectionScoped cs(critical_section_);
+ if (writer_active_ || readers_active_ > 0) {
+ ++writers_waiting_;
+ while (writer_active_ || readers_active_ > 0) {
+ write_condition_->SleepCS(*critical_section_);
+ }
+ --writers_waiting_;
+ }
+ writer_active_ = true;
+}
+
+void RWLockGeneric::ReleaseLockExclusive() {
+ CriticalSectionScoped cs(critical_section_);
+ writer_active_ = false;
+ if (writers_waiting_ > 0) {
+ write_condition_->Wake();
+ } else if (readers_waiting_ > 0) {
+ read_condition_->WakeAll();
+ }
+}
+
+void RWLockGeneric::AcquireLockShared() {
+ CriticalSectionScoped cs(critical_section_);
+ if (writer_active_ || writers_waiting_ > 0) {
+ ++readers_waiting_;
+
+ while (writer_active_ || writers_waiting_ > 0) {
+ read_condition_->SleepCS(*critical_section_);
+ }
+ --readers_waiting_;
+ }
+ ++readers_active_;
+}
+
+void RWLockGeneric::ReleaseLockShared() {
+ CriticalSectionScoped cs(critical_section_);
+ --readers_active_;
+ if (readers_active_ == 0 && writers_waiting_ > 0) {
+ write_condition_->Wake();
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rw_lock_generic.h b/webrtc/system_wrappers/source/rw_lock_generic.h
new file mode 100644
index 0000000000..f0d445692e
--- /dev/null
+++ b/webrtc/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 "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+class CriticalSectionWrapper;
+class ConditionVariableWrapper;
+
+class RWLockGeneric : public RWLockWrapper {
+ public:
+ RWLockGeneric();
+ ~RWLockGeneric() override;
+
+ void AcquireLockExclusive() override;
+ void ReleaseLockExclusive() override;
+
+ void AcquireLockShared() override;
+ void ReleaseLockShared() override;
+
+ private:
+ CriticalSectionWrapper* critical_section_;
+ ConditionVariableWrapper* read_condition_;
+ ConditionVariableWrapper* write_condition_;
+
+ int readers_active_;
+ bool writer_active_;
+ int readers_waiting_;
+ int writers_waiting_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_
diff --git a/webrtc/system_wrappers/source/rw_lock_posix.cc b/webrtc/system_wrappers/source/rw_lock_posix.cc
new file mode 100644
index 0000000000..cdcb7fb5bd
--- /dev/null
+++ b/webrtc/system_wrappers/source/rw_lock_posix.cc
@@ -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.
+ */
+
+#include "webrtc/system_wrappers/source/rw_lock_posix.h"
+
+namespace webrtc {
+
+RWLockPosix::RWLockPosix() : lock_() {
+}
+
+RWLockPosix::~RWLockPosix() {
+ pthread_rwlock_destroy(&lock_);
+}
+
+RWLockPosix* RWLockPosix::Create() {
+ RWLockPosix* ret_val = new RWLockPosix();
+ if (!ret_val->Init()) {
+ delete ret_val;
+ return NULL;
+ }
+ return ret_val;
+}
+
+bool RWLockPosix::Init() {
+ return pthread_rwlock_init(&lock_, 0) == 0;
+}
+
+void RWLockPosix::AcquireLockExclusive() {
+ pthread_rwlock_wrlock(&lock_);
+}
+
+void RWLockPosix::ReleaseLockExclusive() {
+ pthread_rwlock_unlock(&lock_);
+}
+
+void RWLockPosix::AcquireLockShared() {
+ pthread_rwlock_rdlock(&lock_);
+}
+
+void RWLockPosix::ReleaseLockShared() {
+ pthread_rwlock_unlock(&lock_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rw_lock_posix.h b/webrtc/system_wrappers/source/rw_lock_posix.h
new file mode 100644
index 0000000000..0ce7305b60
--- /dev/null
+++ b/webrtc/system_wrappers/source/rw_lock_posix.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_SOURCE_RW_LOCK_POSIX_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
+
+#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+#include "webrtc/typedefs.h"
+
+#include <pthread.h>
+
+namespace webrtc {
+
+class RWLockPosix : public RWLockWrapper {
+ public:
+ static RWLockPosix* Create();
+ ~RWLockPosix() override;
+
+ void AcquireLockExclusive() override;
+ void ReleaseLockExclusive() override;
+
+ void AcquireLockShared() override;
+ void ReleaseLockShared() override;
+
+ private:
+ RWLockPosix();
+ bool Init();
+
+ pthread_rwlock_t lock_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
diff --git a/webrtc/system_wrappers/source/rw_lock_win.cc b/webrtc/system_wrappers/source/rw_lock_win.cc
new file mode 100644
index 0000000000..2372b9b503
--- /dev/null
+++ b/webrtc/system_wrappers/source/rw_lock_win.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/rw_lock_win.h"
+
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+
+static bool native_rw_locks_supported = false;
+static bool module_load_attempted = false;
+static HMODULE library = NULL;
+
+typedef void (WINAPI* InitializeSRWLock)(PSRWLOCK);
+
+typedef void (WINAPI* AcquireSRWLockExclusive)(PSRWLOCK);
+typedef void (WINAPI* ReleaseSRWLockExclusive)(PSRWLOCK);
+
+typedef void (WINAPI* AcquireSRWLockShared)(PSRWLOCK);
+typedef void (WINAPI* ReleaseSRWLockShared)(PSRWLOCK);
+
+InitializeSRWLock initialize_srw_lock;
+AcquireSRWLockExclusive acquire_srw_lock_exclusive;
+AcquireSRWLockShared acquire_srw_lock_shared;
+ReleaseSRWLockShared release_srw_lock_shared;
+ReleaseSRWLockExclusive release_srw_lock_exclusive;
+
+RWLockWin::RWLockWin() {
+ initialize_srw_lock(&lock_);
+}
+
+RWLockWin* RWLockWin::Create() {
+ if (!LoadModule()) {
+ return NULL;
+ }
+ return new RWLockWin();
+}
+
+void RWLockWin::AcquireLockExclusive() {
+ acquire_srw_lock_exclusive(&lock_);
+}
+
+void RWLockWin::ReleaseLockExclusive() {
+ release_srw_lock_exclusive(&lock_);
+}
+
+void RWLockWin::AcquireLockShared() {
+ acquire_srw_lock_shared(&lock_);
+}
+
+void RWLockWin::ReleaseLockShared() {
+ release_srw_lock_shared(&lock_);
+}
+
+bool RWLockWin::LoadModule() {
+ if (module_load_attempted) {
+ return native_rw_locks_supported;
+ }
+ module_load_attempted = true;
+ // Use native implementation if supported (i.e Vista+)
+ library = LoadLibrary(TEXT("Kernel32.dll"));
+ if (!library) {
+ return false;
+ }
+ WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll");
+
+ initialize_srw_lock =
+ (InitializeSRWLock)GetProcAddress(library, "InitializeSRWLock");
+
+ acquire_srw_lock_exclusive =
+ (AcquireSRWLockExclusive)GetProcAddress(library,
+ "AcquireSRWLockExclusive");
+ release_srw_lock_exclusive =
+ (ReleaseSRWLockExclusive)GetProcAddress(library,
+ "ReleaseSRWLockExclusive");
+ acquire_srw_lock_shared =
+ (AcquireSRWLockShared)GetProcAddress(library, "AcquireSRWLockShared");
+ release_srw_lock_shared =
+ (ReleaseSRWLockShared)GetProcAddress(library, "ReleaseSRWLockShared");
+
+ if (initialize_srw_lock && acquire_srw_lock_exclusive &&
+ release_srw_lock_exclusive && acquire_srw_lock_shared &&
+ release_srw_lock_shared) {
+ WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Native RW Lock");
+ native_rw_locks_supported = true;
+ }
+ return native_rw_locks_supported;
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/rw_lock_win.h b/webrtc/system_wrappers/source/rw_lock_win.h
new file mode 100644
index 0000000000..c279eaba44
--- /dev/null
+++ b/webrtc/system_wrappers/source/rw_lock_win.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 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_WIN_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
+
+#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
+
+#include <Windows.h>
+
+namespace webrtc {
+
+class RWLockWin : public RWLockWrapper {
+ public:
+ static RWLockWin* Create();
+ ~RWLockWin() {}
+
+ virtual void AcquireLockExclusive();
+ virtual void ReleaseLockExclusive();
+
+ virtual void AcquireLockShared();
+ virtual void ReleaseLockShared();
+
+ private:
+ RWLockWin();
+ static bool LoadModule();
+
+ SRWLOCK lock_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
diff --git a/webrtc/system_wrappers/source/scoped_vector_unittest.cc b/webrtc/system_wrappers/source/scoped_vector_unittest.cc
new file mode 100644
index 0000000000..b049e4a340
--- /dev/null
+++ b/webrtc/system_wrappers/source/scoped_vector_unittest.cc
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2014 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.
+ */
+
+// Borrowed from Chromium's src/base/memory/scoped_vector_unittest.cc
+
+#include "webrtc/system_wrappers/include/scoped_vector.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace webrtc {
+namespace {
+
+// The LifeCycleObject notifies its Observer upon construction & destruction.
+class LifeCycleObject {
+ public:
+ class Observer {
+ public:
+ virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0;
+ virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ ~LifeCycleObject() {
+ observer_->OnLifeCycleDestroy(this);
+ }
+
+ private:
+ friend class LifeCycleWatcher;
+
+ explicit LifeCycleObject(Observer* observer)
+ : observer_(observer) {
+ observer_->OnLifeCycleConstruct(this);
+ }
+
+ Observer* observer_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
+};
+
+// The life cycle states we care about for the purposes of testing ScopedVector
+// against objects.
+enum LifeCycleState {
+ LC_INITIAL,
+ LC_CONSTRUCTED,
+ LC_DESTROYED,
+};
+
+// Because we wish to watch the life cycle of an object being constructed and
+// destroyed, and further wish to test expectations against the state of that
+// object, we cannot save state in that object itself. Instead, we use this
+// pairing of the watcher, which observes the object and notifies of
+// construction & destruction. Since we also may be testing assumptions about
+// things not getting freed, this class also acts like a scoping object and
+// deletes the |constructed_life_cycle_object_|, if any when the
+// LifeCycleWatcher is destroyed. To keep this simple, the only expected state
+// changes are:
+// INITIAL -> CONSTRUCTED -> DESTROYED.
+// Anything more complicated than that should start another test.
+class LifeCycleWatcher : public LifeCycleObject::Observer {
+ public:
+ LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
+ virtual ~LifeCycleWatcher() {}
+
+ // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
+ // LifeCycleWatcher.
+ void OnLifeCycleConstruct(LifeCycleObject* object) override {
+ ASSERT_EQ(LC_INITIAL, life_cycle_state_);
+ ASSERT_EQ(NULL, constructed_life_cycle_object_.get());
+ life_cycle_state_ = LC_CONSTRUCTED;
+ constructed_life_cycle_object_.reset(object);
+ }
+
+ // Assert CONSTRUCTED -> DESTROYED and the |object| being destroyed is the
+ // same one we saw constructed.
+ void OnLifeCycleDestroy(LifeCycleObject* object) override {
+ ASSERT_EQ(LC_CONSTRUCTED, life_cycle_state_);
+ LifeCycleObject* constructed_life_cycle_object =
+ constructed_life_cycle_object_.release();
+ ASSERT_EQ(constructed_life_cycle_object, object);
+ life_cycle_state_ = LC_DESTROYED;
+ }
+
+ LifeCycleState life_cycle_state() const { return life_cycle_state_; }
+
+ // Factory method for creating a new LifeCycleObject tied to this
+ // LifeCycleWatcher.
+ LifeCycleObject* NewLifeCycleObject() {
+ return new LifeCycleObject(this);
+ }
+
+ // Returns true iff |object| is the same object that this watcher is tracking.
+ bool IsWatching(LifeCycleObject* object) const {
+ return object == constructed_life_cycle_object_.get();
+ }
+
+ private:
+ LifeCycleState life_cycle_state_;
+ rtc::scoped_ptr<LifeCycleObject> constructed_life_cycle_object_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher);
+};
+
+TEST(ScopedVectorTest, LifeCycleWatcher) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ LifeCycleObject* object = watcher.NewLifeCycleObject();
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ delete object;
+ EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, PopBack) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.push_back(watcher.NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+ scoped_vector.pop_back();
+ EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+ EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, Clear) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.push_back(watcher.NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+ scoped_vector.clear();
+ EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+ EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, WeakClear) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.push_back(watcher.NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+ scoped_vector.weak_clear();
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, ResizeShrink) {
+ LifeCycleWatcher first_watcher;
+ EXPECT_EQ(LC_INITIAL, first_watcher.life_cycle_state());
+ LifeCycleWatcher second_watcher;
+ EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
+ ScopedVector<LifeCycleObject> scoped_vector;
+
+ scoped_vector.push_back(first_watcher.NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+ EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
+ EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
+ EXPECT_FALSE(second_watcher.IsWatching(scoped_vector[0]));
+
+ scoped_vector.push_back(second_watcher.NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+ EXPECT_EQ(LC_CONSTRUCTED, second_watcher.life_cycle_state());
+ EXPECT_FALSE(first_watcher.IsWatching(scoped_vector[1]));
+ EXPECT_TRUE(second_watcher.IsWatching(scoped_vector[1]));
+
+ // Test that shrinking a vector deletes elements in the disappearing range.
+ scoped_vector.resize(1);
+ EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+ EXPECT_EQ(LC_DESTROYED, second_watcher.life_cycle_state());
+ EXPECT_EQ(1u, scoped_vector.size());
+ EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
+}
+
+TEST(ScopedVectorTest, ResizeGrow) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.push_back(watcher.NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+ scoped_vector.resize(5);
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ ASSERT_EQ(5u, scoped_vector.size());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector[0]));
+ EXPECT_FALSE(watcher.IsWatching(scoped_vector[1]));
+ EXPECT_FALSE(watcher.IsWatching(scoped_vector[2]));
+ EXPECT_FALSE(watcher.IsWatching(scoped_vector[3]));
+ EXPECT_FALSE(watcher.IsWatching(scoped_vector[4]));
+}
+
+TEST(ScopedVectorTest, Scope) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ {
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.push_back(watcher.NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+ }
+ EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, MoveConstruct) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ {
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.push_back(watcher.NewLifeCycleObject());
+ EXPECT_FALSE(scoped_vector.empty());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+ ScopedVector<LifeCycleObject> scoped_vector_copy(scoped_vector.Pass());
+ EXPECT_TRUE(scoped_vector.empty());
+ EXPECT_FALSE(scoped_vector_copy.empty());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
+
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ }
+ EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, MoveAssign) {
+ LifeCycleWatcher watcher;
+ EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+ {
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.push_back(watcher.NewLifeCycleObject());
+ ScopedVector<LifeCycleObject> scoped_vector_assign;
+ EXPECT_FALSE(scoped_vector.empty());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+ scoped_vector_assign = scoped_vector.Pass();
+ EXPECT_TRUE(scoped_vector.empty());
+ EXPECT_FALSE(scoped_vector_assign.empty());
+ EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
+
+ EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+ }
+ EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+class DeleteCounter {
+ public:
+ explicit DeleteCounter(int* deletes)
+ : deletes_(deletes) {
+ }
+
+ ~DeleteCounter() {
+ (*deletes_)++;
+ }
+
+ void VoidMethod0() {}
+
+ private:
+ int* const deletes_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(DeleteCounter);
+};
+
+// This class is used in place of Chromium's base::Callback.
+template <typename T>
+class PassThru {
+ public:
+ explicit PassThru(ScopedVector<T> scoper) : scoper_(scoper.Pass()) {}
+
+ ScopedVector<T> Run() {
+ return scoper_.Pass();
+ }
+
+ private:
+ ScopedVector<T> scoper_;
+};
+
+TEST(ScopedVectorTest, Passed) {
+ int deletes = 0;
+ ScopedVector<DeleteCounter> deleter_vector;
+ deleter_vector.push_back(new DeleteCounter(&deletes));
+ EXPECT_EQ(0, deletes);
+ PassThru<DeleteCounter> pass_thru(deleter_vector.Pass());
+ EXPECT_EQ(0, deletes);
+ ScopedVector<DeleteCounter> result = pass_thru.Run();
+ EXPECT_EQ(0, deletes);
+ result.clear();
+ EXPECT_EQ(1, deletes);
+};
+
+TEST(ScopedVectorTest, InsertRange) {
+ LifeCycleWatcher watchers[5];
+ size_t watchers_size = sizeof(watchers) / sizeof(*watchers);
+
+ std::vector<LifeCycleObject*> vec;
+ for (LifeCycleWatcher* it = watchers; it != watchers + watchers_size;
+ ++it) {
+ EXPECT_EQ(LC_INITIAL, it->life_cycle_state());
+ vec.push_back(it->NewLifeCycleObject());
+ EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+ }
+ // Start scope for ScopedVector.
+ {
+ ScopedVector<LifeCycleObject> scoped_vector;
+ scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3);
+ for (LifeCycleWatcher* it = watchers; it != watchers + watchers_size;
+ ++it)
+ EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+ }
+ for (LifeCycleWatcher* it = watchers; it != watchers + 1; ++it)
+ EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+ for (LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it)
+ EXPECT_EQ(LC_DESTROYED, it->life_cycle_state());
+ for (LifeCycleWatcher* it = watchers + 3; it != watchers + watchers_size;
+ ++it)
+ EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/sleep.cc b/webrtc/system_wrappers/source/sleep.cc
new file mode 100644
index 0000000000..181381fd53
--- /dev/null
+++ b/webrtc/system_wrappers/source/sleep.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 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.
+ */
+// An OS-independent sleep function.
+
+#include "webrtc/system_wrappers/include/sleep.h"
+
+#ifdef _WIN32
+// For Sleep()
+#include <windows.h>
+#else
+// For nanosleep()
+#include <time.h>
+#endif
+
+namespace webrtc {
+
+void SleepMs(int msecs) {
+#ifdef _WIN32
+ Sleep(msecs);
+#else
+ struct timespec short_wait;
+ struct timespec remainder;
+ short_wait.tv_sec = msecs / 1000;
+ short_wait.tv_nsec = (msecs % 1000) * 1000 * 1000;
+ nanosleep(&short_wait, &remainder);
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/sort.cc b/webrtc/system_wrappers/source/sort.cc
new file mode 100644
index 0000000000..f166f95311
--- /dev/null
+++ b/webrtc/system_wrappers/source/sort.cc
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/sort.h"
+
+#include <assert.h>
+#include <string.h> // memcpy
+
+#include <new> // nothrow new
+
+#ifdef NO_STL
+#include <stdlib.h> // qsort
+#else
+#include <algorithm> // std::sort
+#include <vector>
+
+// TODO(ajm) upgrade to spreadsort v2.
+#include "webrtc/system_wrappers/source/spreadsortlib/spreadsort.hpp"
+#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<TYPE>(*static_cast<const TYPE*>(X)); \
+ TYPE yT = static_cast<TYPE>(*static_cast<const TYPE*>(Y)); \
+ COMPARE_DEREFERENCED(xT, yT); \
+ } while(0)
+
+#define COMPARE_KEY_FOR_QSORT(SORT_KEY_X, SORT_KEY_Y, TYPE) \
+ do { \
+ TYPE xT = static_cast<TYPE>( \
+ *static_cast<TYPE*>(static_cast<const SortKey*>(SORT_KEY_X)->key_)); \
+ TYPE yT = static_cast<TYPE>( \
+ *static_cast<TYPE*>(static_cast<const SortKey*>(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* key_type = (KEY_TYPE*)(key); \
+ for (uint32_t i = 0; i < (NUM_OF_ELEMENTS); ++i) { \
+ ptr_sort_key[i].key_ = &key_type[i]; \
+ ptr_sort_key[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_;
+ uint32_t index_;
+};
+#else
+template<typename KeyType>
+struct SortKey {
+ KeyType key_;
+ uint32_t index_;
+};
+#endif
+
+namespace { // Unnamed namespace provides internal linkage.
+
+#ifdef NO_STL
+int CompareWord8(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, int8_t);
+}
+
+int CompareUWord8(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, uint8_t);
+}
+
+int CompareWord16(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, int16_t);
+}
+
+int CompareUWord16(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, uint16_t);
+}
+
+int CompareWord32(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, int32_t);
+}
+
+int CompareUWord32(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, uint32_t);
+}
+
+int CompareWord64(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, int64_t);
+}
+
+int CompareUWord64(const void* x, const void* y) {
+ COMPARE_FOR_QSORT(x, y, uint64_t);
+}
+
+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* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int8_t);
+}
+
+int CompareKeyUWord8(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint8_t);
+}
+
+int CompareKeyWord16(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int16_t);
+}
+
+int CompareKeyUWord16(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint16_t);
+}
+
+int CompareKeyWord32(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int32_t);
+}
+
+int CompareKeyUWord32(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint32_t);
+}
+
+int CompareKeyWord64(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, int64_t);
+}
+
+int CompareKeyUWord64(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, uint64_t);
+}
+
+int CompareKeyFloat32(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, float);
+}
+
+int CompareKeyFloat64(const void* sort_key_x, const void* sort_key_y) {
+ COMPARE_KEY_FOR_QSORT(sort_key_x, sort_key_y, double);
+}
+#else
+template <typename KeyType>
+struct KeyLessThan {
+ bool operator()(const SortKey<KeyType>& sort_key_x,
+ const SortKey<KeyType>& sort_key_y) const {
+ return sort_key_x.key_ < sort_key_y.key_;
+ }
+};
+
+template <typename KeyType>
+struct KeyRightShift {
+ KeyType operator()(const SortKey<KeyType>& sort_key,
+ const unsigned offset) const {
+ return sort_key.key_ >> offset;
+ }
+};
+
+template <typename DataType>
+inline void IntegerSort(void* data, uint32_t num_of_elements) {
+ DataType* data_type = static_cast<DataType*>(data);
+ boost::integer_sort(data_type, data_type + num_of_elements);
+}
+
+template <typename DataType, typename IntegerType>
+inline void FloatSort(void* data, uint32_t num_of_elements) {
+ DataType* data_type = static_cast<DataType*>(data);
+ IntegerType c_val = 0;
+ boost::float_sort_cast(data_type, data_type + num_of_elements, c_val);
+}
+
+template <typename DataType>
+inline void StdSort(void* data, uint32_t num_of_elements) {
+ DataType* data_type = static_cast<DataType*>(data);
+ std::sort(data_type, data_type + num_of_elements);
+}
+
+template<typename KeyType>
+inline int32_t SetupKeySort(void* key,
+ SortKey<KeyType>*& ptr_sort_key,
+ uint32_t num_of_elements) {
+ ptr_sort_key = new(std::nothrow) SortKey<KeyType>[num_of_elements];
+ if (ptr_sort_key == NULL) {
+ return -1;
+ }
+
+ KeyType* key_type = static_cast<KeyType*>(key);
+ for (uint32_t i = 0; i < num_of_elements; i++) {
+ ptr_sort_key[i].key_ = key_type[i];
+ ptr_sort_key[i].index_ = i;
+ }
+
+ return 0;
+}
+
+template<typename KeyType>
+inline int32_t TeardownKeySort(void* data,
+ SortKey<KeyType>* ptr_sort_key,
+ uint32_t num_of_elements,
+ uint32_t size_of_element) {
+ uint8_t* ptr_data = static_cast<uint8_t*>(data);
+ uint8_t* ptr_data_sorted =
+ new(std::nothrow) uint8_t[num_of_elements * size_of_element];
+ if (ptr_data_sorted == NULL) {
+ return -1;
+ }
+
+ for (uint32_t i = 0; i < num_of_elements; i++) {
+ memcpy(ptr_data_sorted + i * size_of_element, ptr_data +
+ ptr_sort_key[i].index_ * size_of_element, size_of_element);
+ }
+ memcpy(ptr_data, ptr_data_sorted, num_of_elements * size_of_element);
+ delete[] ptr_sort_key;
+ delete[] ptr_data_sorted;
+ return 0;
+}
+
+template<typename KeyType>
+inline int32_t IntegerKeySort(void* data, void* key,
+ uint32_t num_of_elements,
+ uint32_t size_of_element) {
+ SortKey<KeyType>* ptr_sort_key;
+ if (SetupKeySort<KeyType>(key, ptr_sort_key, num_of_elements) != 0) {
+ return -1;
+ }
+
+ boost::integer_sort(ptr_sort_key, ptr_sort_key + num_of_elements,
+ KeyRightShift<KeyType>(), KeyLessThan<KeyType>());
+
+ if (TeardownKeySort<KeyType>(data, ptr_sort_key, num_of_elements,
+ size_of_element) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+template<typename KeyType>
+inline int32_t StdKeySort(void* data, void* key,
+ uint32_t num_of_elements,
+ uint32_t size_of_element) {
+ SortKey<KeyType>* ptr_sort_key;
+ if (SetupKeySort<KeyType>(key, ptr_sort_key, num_of_elements) != 0) {
+ return -1;
+ }
+
+ std::sort(ptr_sort_key, ptr_sort_key + num_of_elements,
+ KeyLessThan<KeyType>());
+
+ if (TeardownKeySort<KeyType>(data, ptr_sort_key, num_of_elements,
+ size_of_element) != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+}
+
+int32_t Sort(void* data, uint32_t num_of_elements, Type type) {
+ if (data == NULL) {
+ return -1;
+ }
+
+#ifdef NO_STL
+ switch (type) {
+ case TYPE_Word8:
+ qsort(data, num_of_elements, sizeof(int8_t), CompareWord8);
+ break;
+ case TYPE_UWord8:
+ qsort(data, num_of_elements, sizeof(uint8_t), CompareUWord8);
+ break;
+ case TYPE_Word16:
+ qsort(data, num_of_elements, sizeof(int16_t), CompareWord16);
+ break;
+ case TYPE_UWord16:
+ qsort(data, num_of_elements, sizeof(uint16_t), CompareUWord16);
+ break;
+ case TYPE_Word32:
+ qsort(data, num_of_elements, sizeof(int32_t), CompareWord32);
+ break;
+ case TYPE_UWord32:
+ qsort(data, num_of_elements, sizeof(uint32_t), CompareUWord32);
+ break;
+ case TYPE_Word64:
+ qsort(data, num_of_elements, sizeof(int64_t), CompareWord64);
+ break;
+ case TYPE_UWord64:
+ qsort(data, num_of_elements, sizeof(uint64_t), CompareUWord64);
+ break;
+ case TYPE_Float32:
+ qsort(data, num_of_elements, sizeof(float), CompareFloat32);
+ break;
+ case TYPE_Float64:
+ qsort(data, num_of_elements, 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<int8_t>(data, num_of_elements);
+ break;
+ case TYPE_UWord8:
+ IntegerSort<uint8_t>(data, num_of_elements);
+ break;
+ case TYPE_Word16:
+ IntegerSort<int16_t>(data, num_of_elements);
+ break;
+ case TYPE_UWord16:
+ IntegerSort<uint16_t>(data, num_of_elements);
+ break;
+ case TYPE_Word32:
+ IntegerSort<int32_t>(data, num_of_elements);
+ break;
+ case TYPE_UWord32:
+ IntegerSort<uint32_t>(data, num_of_elements);
+ break;
+ case TYPE_Word64:
+ StdSort<int64_t>(data, num_of_elements);
+ break;
+ case TYPE_UWord64:
+ StdSort<uint64_t>(data, num_of_elements);
+ break;
+ case TYPE_Float32:
+ StdSort<float>(data, num_of_elements);
+ break;
+ case TYPE_Float64:
+ StdSort<double>(data, num_of_elements);
+ break;
+ }
+#endif
+ return 0;
+}
+
+int32_t KeySort(void* data, void* key, uint32_t num_of_elements,
+ uint32_t size_of_element, Type key_type) {
+ if (data == NULL) {
+ return -1;
+ }
+
+ if (key == NULL) {
+ return -1;
+ }
+
+ if ((uint64_t)num_of_elements * size_of_element > 0xffffffff) {
+ return -1;
+ }
+
+#ifdef NO_STL
+ SortKey* ptr_sort_key = new(std::nothrow) SortKey[num_of_elements];
+ if (ptr_sort_key == NULL) {
+ return -1;
+ }
+
+ switch (key_type) {
+ case TYPE_Word8:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, int8_t,
+ CompareKeyWord8);
+ break;
+ case TYPE_UWord8:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, uint8_t,
+ CompareKeyUWord8);
+ break;
+ case TYPE_Word16:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, int16_t,
+ CompareKeyWord16);
+ break;
+ case TYPE_UWord16:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, uint16_t,
+ CompareKeyUWord16);
+ break;
+ case TYPE_Word32:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, int32_t,
+ CompareKeyWord32);
+ break;
+ case TYPE_UWord32:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, uint32_t,
+ CompareKeyUWord32);
+ break;
+ case TYPE_Word64:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, int64_t,
+ CompareKeyWord64);
+ break;
+ case TYPE_UWord64:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, uint64_t,
+ CompareKeyUWord64);
+ break;
+ case TYPE_Float32:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, float,
+ CompareKeyFloat32);
+ break;
+ case TYPE_Float64:
+ KEY_QSORT(ptr_sort_key, key, num_of_elements, double,
+ CompareKeyFloat64);
+ break;
+ default:
+ return -1;
+ }
+
+ // Shuffle into sorted position based on index map.
+ uint8_t* ptr_data = static_cast<uint8_t*>(data);
+ uint8_t* ptr_data_sorted =
+ new(std::nothrow) uint8_t[num_of_elements * size_of_element];
+ if (ptr_data_sorted == NULL) {
+ return -1;
+ }
+
+ for (uint32_t i = 0; i < num_of_elements; i++) {
+ memcpy(ptr_data_sorted + i * size_of_element, ptr_data +
+ ptr_sort_key[i].index_ * size_of_element, size_of_element);
+ }
+ memcpy(ptr_data, ptr_data_sorted, num_of_elements * size_of_element);
+
+ delete[] ptr_sort_key;
+ delete[] ptr_data_sorted;
+
+ return 0;
+#else
+ // Fall back to std::sort for 64-bit types and floats due to compiler
+ // warnings and errors respectively with spreadsort.
+ switch (key_type) {
+ case TYPE_Word8:
+ return IntegerKeySort<int8_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_UWord8:
+ return IntegerKeySort<uint8_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_Word16:
+ return IntegerKeySort<int16_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_UWord16:
+ return IntegerKeySort<uint16_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_Word32:
+ return IntegerKeySort<int32_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_UWord32:
+ return IntegerKeySort<uint32_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_Word64:
+ return StdKeySort<int64_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_UWord64:
+ return StdKeySort<uint64_t>(data, key, num_of_elements,
+ size_of_element);
+ case TYPE_Float32:
+ return StdKeySort<float>(data, key, num_of_elements, size_of_element);
+ case TYPE_Float64:
+ return StdKeySort<double>(data, key, num_of_elements, size_of_element);
+ }
+ assert(false);
+ return -1;
+#endif
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/spreadsortlib/constants.hpp b/webrtc/system_wrappers/source/spreadsortlib/constants.hpp
new file mode 100644
index 0000000000..fa81ece869
--- /dev/null
+++ b/webrtc/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/webrtc/system_wrappers/source/spreadsortlib/spreadsort.hpp b/webrtc/system_wrappers/source/spreadsortlib/spreadsort.hpp
new file mode 100644
index 0000000000..96b0bcf44e
--- /dev/null
+++ b/webrtc/system_wrappers/source/spreadsortlib/spreadsort.hpp
@@ -0,0 +1,1693 @@
+//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 <algorithm>
+#include <cstring>
+#include <vector>
+#include "webrtc/system_wrappers/source/spreadsortlib/constants.hpp"
+
+#ifdef getchar
+// This file should not use getchar as a template parameter name.
+#undef getchar
+#endif
+
+namespace boost {
+ namespace detail {
+ //This only works on unsigned data types
+ template <typename T>
+ 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 <class RandomAccessIter>
+ 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 <class RandomAccessIter, class compare>
+ 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 <class RandomAccessIter>
+ inline RandomAccessIter *
+ size_bins(std::vector<size_t> &bin_sizes, std::vector<RandomAccessIter> &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 <class RandomAccessIter, class div_type, class data_type>
+ inline void
+ spread_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<RandomAccessIter, div_type, data_type>(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes);
+ }
+ }
+
+ //Generic bitshift-based 3-way swapping code
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift>
+ 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 <class RandomAccessIter, class div_type, class data_type, class right_shift>
+ inline void swap_loop(RandomAccessIter * bins, RandomAccessIter & nextbinstart, unsigned ii, right_shift &shift
+ , const std::vector<size_t> &bin_sizes, const unsigned log_divisor, const div_type div_min)
+ {
+ nextbinstart += bin_sizes[ii];
+ inner_swap_loop<RandomAccessIter, div_type, data_type, right_shift>(bins, nextbinstart, ii, shift, log_divisor, div_min);
+ }
+
+ //Functor implementation for recursive sorting
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift, class compare>
+ inline void
+ spread_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift, compare>(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift, comp);
+ }
+ }
+
+ //Functor implementation for recursive sorting with only Shift overridden
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift>
+ inline void
+ spread_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift>(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift);
+ }
+ }
+
+ //Holds the bin vector and makes the initial recursive call
+ template <class RandomAccessIter, class div_type, class data_type>
+ inline void
+ spread_sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ spread_sort_rec<RandomAccessIter, div_type, data_type>(first, last, bin_cache, 0, bin_sizes);
+ }
+
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift, class compare>
+ inline void
+ spread_sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift, compare comp)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ spread_sort_rec<RandomAccessIter, div_type, data_type, right_shift, compare>(first, last, bin_cache, 0, bin_sizes, shift, comp);
+ }
+
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift>
+ inline void
+ spread_sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ spread_sort_rec<RandomAccessIter, div_type, data_type, right_shift>(first, last, bin_cache, 0, bin_sizes, shift);
+ }
+ }
+
+ //Top-level sorting call for integers
+ template <class RandomAccessIter>
+ 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 <class RandomAccessIter, class right_shift, class compare>
+ 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 <class RandomAccessIter, class right_shift>
+ 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<class cast_type, class RandomAccessIter>
+ 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<class data_type, class cast_type>
+ inline cast_type
+ mem_cast(const data_type & data)
+ {
+ cast_type result;
+ std::memcpy(&result, &data, sizeof(cast_type));
+ return result;
+ }
+
+ namespace detail {
+ template <class RandomAccessIter, class div_type, class right_shift>
+ 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 <class RandomAccessIter, class div_type, class data_type>
+ 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<div_type, RandomAccessIter>(current) >> log_divisor) - div_min)); target_bin != local_bin;
+ target_bin = bins + ((cast_float_iter<div_type, RandomAccessIter>(current) >> log_divisor) - div_min)) {
+ data_type tmp;
+ RandomAccessIter b = (*target_bin)++;
+ RandomAccessIter * b_bin = bins + ((cast_float_iter<div_type, RandomAccessIter>(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 <class RandomAccessIter, class div_type, class data_type>
+ inline void float_swap_loop(RandomAccessIter * bins, RandomAccessIter & nextbinstart, unsigned ii
+ , const std::vector<size_t> &bin_sizes, const unsigned log_divisor, const div_type div_min)
+ {
+ nextbinstart += bin_sizes[ii];
+ inner_float_swap_loop<RandomAccessIter, div_type, data_type>(bins, nextbinstart, ii, log_divisor, div_min);
+ }
+
+ template <class RandomAccessIter, class cast_type>
+ inline void
+ find_extremes(RandomAccessIter current, RandomAccessIter last, cast_type & max, cast_type & min)
+ {
+ min = max = cast_float_iter<cast_type, RandomAccessIter>(current);
+ while(++current < last) {
+ cast_type value = cast_float_iter<cast_type, RandomAccessIter>(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 <class RandomAccessIter, class div_type, class data_type>
+ inline void
+ positive_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<div_type, RandomAccessIter>(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<RandomAccessIter, div_type, data_type>(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<RandomAccessIter, div_type, data_type>(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 <class RandomAccessIter, class div_type, class data_type>
+ inline void
+ negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<div_type, RandomAccessIter>(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<RandomAccessIter, div_type, data_type>(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<RandomAccessIter, div_type, data_type>(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 <class RandomAccessIter, class div_type, class data_type, class right_shift>
+ inline void
+ negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift>(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, shift);
+ }
+ }
+
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift, class compare>
+ inline void
+ negative_float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift, compare>(lastPos, bin_cache[ii], bin_cache, cache_end, bin_sizes, shift, comp);
+ }
+ }
+
+ //Casting special-case for floating-point sorting
+ template <class RandomAccessIter, class div_type, class data_type>
+ inline void
+ float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<div_type, RandomAccessIter>(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<RandomAccessIter, div_type, data_type>(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<RandomAccessIter, div_type, data_type>(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<RandomAccessIter, div_type, data_type>(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes);
+ }
+ }
+
+ //Functor implementation for recursive sorting
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift>
+ inline void
+ float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift>(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift);
+ }
+ }
+
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift, class compare>
+ inline void
+ float_sort_rec(RandomAccessIter first, RandomAccessIter last, std::vector<RandomAccessIter> &bin_cache, unsigned cache_offset
+ , std::vector<size_t> &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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift>(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<RandomAccessIter, div_type, data_type, right_shift>(lastPos, bin_cache[u], bin_cache, cache_end, bin_sizes, shift, comp);
+ }
+ }
+
+ template <class RandomAccessIter, class cast_type, class data_type>
+ inline void
+ float_Sort(RandomAccessIter first, RandomAccessIter last, cast_type, data_type)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ float_sort_rec<RandomAccessIter, cast_type, data_type>(first, last, bin_cache, 0, bin_sizes);
+ }
+
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift>
+ inline void
+ float_Sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ float_sort_rec<RandomAccessIter, div_type, data_type, right_shift>(first, last, bin_cache, 0, bin_sizes, shift);
+ }
+
+ template <class RandomAccessIter, class div_type, class data_type, class right_shift, class compare>
+ inline void
+ float_Sort(RandomAccessIter first, RandomAccessIter last, div_type, data_type, right_shift shift, compare comp)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ float_sort_rec<RandomAccessIter, div_type, data_type, right_shift>(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 <class RandomAccessIter, class cast_type>
+ 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 <class RandomAccessIter>
+ 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 <class RandomAccessIter, class right_shift>
+ 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 <class RandomAccessIter, class right_shift, class compare>
+ 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<class RandomAccessIter>
+ 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<class RandomAccessIter, class get_char, class get_length>
+ 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<class data_type, class unsignedchar_type>
+ 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<unsignedchar_type>(x[u]) < static_cast<unsignedchar_type>(y[u]))
+ return true;
+ else if(static_cast<unsignedchar_type>(y[u]) < static_cast<unsignedchar_type>(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<class data_type, class unsignedchar_type>
+ 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<unsignedchar_type>(x[u]) > static_cast<unsignedchar_type>(y[u]))
+ return true;
+ else if(static_cast<unsignedchar_type>(y[u]) > static_cast<unsignedchar_type>(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<class data_type, class get_char, class get_length>
+ 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 <class RandomAccessIter, class data_type, class unsignedchar_type>
+ inline void
+ string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector<RandomAccessIter> &bin_cache
+ , unsigned cache_offset, std::vector<size_t> &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<unsignedchar_type>((*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<unsignedchar_type>((*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<unsignedchar_type>((*current)[char_offset]); target_bin != local_bin;
+ target_bin = bins + static_cast<unsignedchar_type>((*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<data_type, unsignedchar_type>(char_offset + 1));
+ else
+ string_sort_rec<RandomAccessIter, data_type, unsignedchar_type>(lastPos, bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes);
+ }
+ }
+
+ //Sorts strings in reverse order, with empties at the end
+ template <class RandomAccessIter, class data_type, class unsignedchar_type>
+ inline void
+ reverse_string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector<RandomAccessIter> &bin_cache
+ , unsigned cache_offset, std::vector<size_t> &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<unsignedchar_type>((*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<unsignedchar_type>((*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<unsignedchar_type>((*current)[char_offset]); target_bin != local_bin;
+ target_bin = end_bin - static_cast<unsignedchar_type>((*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<data_type, unsignedchar_type>(char_offset + 1));
+ else
+ reverse_string_sort_rec<RandomAccessIter, data_type, unsignedchar_type>(lastPos, bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes);
+ }
+ }
+
+ //String sorting recursive implementation
+ template <class RandomAccessIter, class data_type, class unsignedchar_type, class get_char, class get_length>
+ inline void
+ string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector<RandomAccessIter> &bin_cache
+ , unsigned cache_offset, std::vector<size_t> &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<data_type, get_char, get_length>(char_offset + 1));
+ else
+ string_sort_rec<RandomAccessIter, data_type, unsignedchar_type, get_char, get_length>(lastPos, bin_cache[u], char_offset + 1, bin_cache, cache_end, bin_sizes, getchar, length);
+ }
+ }
+
+ //String sorting recursive implementation
+ template <class RandomAccessIter, class data_type, class unsignedchar_type, class get_char, class get_length, class compare>
+ inline void
+ string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector<RandomAccessIter> &bin_cache
+ , unsigned cache_offset, std::vector<size_t> &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<RandomAccessIter, data_type, unsignedchar_type, get_char, get_length, compare>(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 <class RandomAccessIter, class data_type, class unsignedchar_type, class get_char, class get_length, class compare>
+ inline void
+ reverse_string_sort_rec(RandomAccessIter first, RandomAccessIter last, unsigned char_offset, std::vector<RandomAccessIter> &bin_cache
+ , unsigned cache_offset, std::vector<size_t> &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<RandomAccessIter, data_type, unsignedchar_type, get_char, get_length, compare>(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 <class RandomAccessIter, class data_type, class unsignedchar_type>
+ inline void
+ string_sort(RandomAccessIter first, RandomAccessIter last, data_type, unsignedchar_type)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ string_sort_rec<RandomAccessIter, data_type, unsignedchar_type>(first, last, 0, bin_cache, 0, bin_sizes);
+ }
+
+ //Holds the bin vector and makes the initial recursive call
+ template <class RandomAccessIter, class data_type, class unsignedchar_type>
+ inline void
+ reverse_string_sort(RandomAccessIter first, RandomAccessIter last, data_type, unsignedchar_type)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ reverse_string_sort_rec<RandomAccessIter, data_type, unsignedchar_type>(first, last, 0, bin_cache, 0, bin_sizes);
+ }
+
+ //Holds the bin vector and makes the initial recursive call
+ template <class RandomAccessIter, class get_char, class get_length, class data_type, class unsignedchar_type>
+ inline void
+ string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, data_type, unsignedchar_type)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ string_sort_rec<RandomAccessIter, data_type, unsignedchar_type, get_char, get_length>(first, last, 0, bin_cache, 0, bin_sizes, getchar, length);
+ }
+
+ //Holds the bin vector and makes the initial recursive call
+ template <class RandomAccessIter, class get_char, class get_length, class compare, class data_type, class unsignedchar_type>
+ inline void
+ string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, compare comp, data_type, unsignedchar_type)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ string_sort_rec<RandomAccessIter, data_type, unsignedchar_type, get_char, get_length, compare>(first, last, 0, bin_cache, 0, bin_sizes, getchar, length, comp);
+ }
+
+ //Holds the bin vector and makes the initial recursive call
+ template <class RandomAccessIter, class get_char, class get_length, class compare, class data_type, class unsignedchar_type>
+ inline void
+ reverse_string_sort(RandomAccessIter first, RandomAccessIter last, get_char getchar, get_length length, compare comp, data_type, unsignedchar_type)
+ {
+ std::vector<size_t> bin_sizes;
+ std::vector<RandomAccessIter> bin_cache;
+ reverse_string_sort_rec<RandomAccessIter, data_type, unsignedchar_type, get_char, get_length, compare>(first, last, 0, bin_cache, 0, bin_sizes, getchar, length, comp);
+ }
+ }
+
+ //Allows character-type overloads
+ template <class RandomAccessIter, class unsignedchar_type>
+ 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 <class RandomAccessIter>
+ inline void string_sort(RandomAccessIter first, RandomAccessIter last)
+ {
+ unsigned char unused = '\0';
+ string_sort(first, last, unused);
+ }
+
+ //Allows character-type overloads
+ template <class RandomAccessIter, class compare, class unsignedchar_type>
+ 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 <class RandomAccessIter, class compare>
+ inline void reverse_string_sort(RandomAccessIter first, RandomAccessIter last, compare comp)
+ {
+ unsigned char unused = '\0';
+ reverse_string_sort(first, last, comp, unused);
+ }
+
+ template <class RandomAccessIter, class get_char, class get_length>
+ 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 <class RandomAccessIter, class get_char, class get_length, class compare>
+ 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 <class RandomAccessIter, class get_char, class get_length, class compare>
+ 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/webrtc/system_wrappers/source/stl_util_unittest.cc b/webrtc/system_wrappers/source/stl_util_unittest.cc
new file mode 100644
index 0000000000..ed5c1d9590
--- /dev/null
+++ b/webrtc/system_wrappers/source/stl_util_unittest.cc
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2014 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.
+ */
+
+// Borrowed from Chromium's src/base/stl_util_unittest.cc
+#include "webrtc/system_wrappers/include/stl_util.h"
+
+#include <set>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Used as test case to ensure the various base::STLXxx functions don't require
+// more than operators "<" and "==" on values stored in containers.
+class ComparableValue {
+ public:
+ explicit ComparableValue(int value) : value_(value) {}
+
+ bool operator==(const ComparableValue& rhs) const {
+ return value_ == rhs.value_;
+ }
+
+ bool operator<(const ComparableValue& rhs) const {
+ return value_ < rhs.value_;
+ }
+
+ private:
+ int value_;
+};
+
+} // namespace
+
+namespace webrtc {
+namespace {
+
+TEST(STLUtilTest, STLIsSorted) {
+ {
+ std::set<int> set;
+ set.insert(24);
+ set.insert(1);
+ set.insert(12);
+ EXPECT_TRUE(STLIsSorted(set));
+ }
+
+ {
+ std::set<ComparableValue> set;
+ set.insert(ComparableValue(24));
+ set.insert(ComparableValue(1));
+ set.insert(ComparableValue(12));
+ EXPECT_TRUE(STLIsSorted(set));
+ }
+
+ {
+ std::vector<int> vector;
+ vector.push_back(1);
+ vector.push_back(1);
+ vector.push_back(4);
+ vector.push_back(64);
+ vector.push_back(12432);
+ EXPECT_TRUE(STLIsSorted(vector));
+ vector.back() = 1;
+ EXPECT_FALSE(STLIsSorted(vector));
+ }
+}
+
+TEST(STLUtilTest, STLSetDifference) {
+ std::set<int> a1;
+ a1.insert(1);
+ a1.insert(2);
+ a1.insert(3);
+ a1.insert(4);
+
+ std::set<int> a2;
+ a2.insert(3);
+ a2.insert(4);
+ a2.insert(5);
+ a2.insert(6);
+ a2.insert(7);
+
+ {
+ std::set<int> difference;
+ difference.insert(1);
+ difference.insert(2);
+ EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a1, a2));
+ }
+
+ {
+ std::set<int> difference;
+ difference.insert(5);
+ difference.insert(6);
+ difference.insert(7);
+ EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a2, a1));
+ }
+
+ {
+ std::vector<int> difference;
+ difference.push_back(1);
+ difference.push_back(2);
+ EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a1, a2));
+ }
+
+ {
+ std::vector<int> difference;
+ difference.push_back(5);
+ difference.push_back(6);
+ difference.push_back(7);
+ EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a2, a1));
+ }
+}
+
+TEST(STLUtilTest, STLSetUnion) {
+ std::set<int> a1;
+ a1.insert(1);
+ a1.insert(2);
+ a1.insert(3);
+ a1.insert(4);
+
+ std::set<int> a2;
+ a2.insert(3);
+ a2.insert(4);
+ a2.insert(5);
+ a2.insert(6);
+ a2.insert(7);
+
+ {
+ std::set<int> result;
+ result.insert(1);
+ result.insert(2);
+ result.insert(3);
+ result.insert(4);
+ result.insert(5);
+ result.insert(6);
+ result.insert(7);
+ EXPECT_EQ(result, STLSetUnion<std::set<int> >(a1, a2));
+ }
+
+ {
+ std::set<int> result;
+ result.insert(1);
+ result.insert(2);
+ result.insert(3);
+ result.insert(4);
+ result.insert(5);
+ result.insert(6);
+ result.insert(7);
+ EXPECT_EQ(result, STLSetUnion<std::set<int> >(a2, a1));
+ }
+
+ {
+ std::vector<int> result;
+ result.push_back(1);
+ result.push_back(2);
+ result.push_back(3);
+ result.push_back(4);
+ result.push_back(5);
+ result.push_back(6);
+ result.push_back(7);
+ EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a1, a2));
+ }
+
+ {
+ std::vector<int> result;
+ result.push_back(1);
+ result.push_back(2);
+ result.push_back(3);
+ result.push_back(4);
+ result.push_back(5);
+ result.push_back(6);
+ result.push_back(7);
+ EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a2, a1));
+ }
+}
+
+TEST(STLUtilTest, STLSetIntersection) {
+ std::set<int> a1;
+ a1.insert(1);
+ a1.insert(2);
+ a1.insert(3);
+ a1.insert(4);
+
+ std::set<int> a2;
+ a2.insert(3);
+ a2.insert(4);
+ a2.insert(5);
+ a2.insert(6);
+ a2.insert(7);
+
+ {
+ std::set<int> result;
+ result.insert(3);
+ result.insert(4);
+ EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a1, a2));
+ }
+
+ {
+ std::set<int> result;
+ result.insert(3);
+ result.insert(4);
+ EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a2, a1));
+ }
+
+ {
+ std::vector<int> result;
+ result.push_back(3);
+ result.push_back(4);
+ EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a1, a2));
+ }
+
+ {
+ std::vector<int> result;
+ result.push_back(3);
+ result.push_back(4);
+ EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a2, a1));
+ }
+}
+
+TEST(STLUtilTest, STLIncludes) {
+ std::set<int> a1;
+ a1.insert(1);
+ a1.insert(2);
+ a1.insert(3);
+ a1.insert(4);
+
+ std::set<int> a2;
+ a2.insert(3);
+ a2.insert(4);
+
+ std::set<int> a3;
+ a3.insert(3);
+ a3.insert(4);
+ a3.insert(5);
+
+ EXPECT_TRUE(STLIncludes<std::set<int> >(a1, a2));
+ EXPECT_FALSE(STLIncludes<std::set<int> >(a1, a3));
+ EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a1));
+ EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a3));
+ EXPECT_FALSE(STLIncludes<std::set<int> >(a3, a1));
+ EXPECT_TRUE(STLIncludes<std::set<int> >(a3, a2));
+}
+
+} // namespace
+} // namespace webrtc
+
diff --git a/webrtc/system_wrappers/source/stringize_macros_unittest.cc b/webrtc/system_wrappers/source/stringize_macros_unittest.cc
new file mode 100644
index 0000000000..c2f312bf90
--- /dev/null
+++ b/webrtc/system_wrappers/source/stringize_macros_unittest.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2013 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 "webrtc/system_wrappers/include/stringize_macros.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Macros as per documentation in header file.
+#define PREPROCESSOR_UTIL_UNITTEST_A FOO
+#define PREPROCESSOR_UTIL_UNITTEST_B(x) myobj->FunctionCall(x)
+#define PREPROCESSOR_UTIL_UNITTEST_C "foo"
+
+TEST(StringizeTest, Ansi) {
+ EXPECT_STREQ(
+ "PREPROCESSOR_UTIL_UNITTEST_A",
+ STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A));
+ EXPECT_STREQ(
+ "PREPROCESSOR_UTIL_UNITTEST_B(y)",
+ STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+ EXPECT_STREQ(
+ "PREPROCESSOR_UTIL_UNITTEST_C",
+ STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C));
+
+ EXPECT_STREQ("FOO", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_A));
+ EXPECT_STREQ("myobj->FunctionCall(y)",
+ STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+ EXPECT_STREQ("\"foo\"", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_C));
+}
diff --git a/webrtc/system_wrappers/source/thread.cc b/webrtc/system_wrappers/source/thread.cc
new file mode 100644
index 0000000000..7da1e3d591
--- /dev/null
+++ b/webrtc/system_wrappers/source/thread.cc
@@ -0,0 +1,33 @@
+/*
+ * 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 "webrtc/system_wrappers/include/thread_wrapper.h"
+
+#if defined(_WIN32)
+#include "webrtc/system_wrappers/source/thread_win.h"
+#else
+#include "webrtc/system_wrappers/source/thread_posix.h"
+#endif
+
+namespace webrtc {
+
+#if defined(_WIN32)
+typedef ThreadWindows ThreadType;
+#else
+typedef ThreadPosix ThreadType;
+#endif
+
+rtc::scoped_ptr<ThreadWrapper> ThreadWrapper::CreateThread(
+ ThreadRunFunction func, void* obj, const char* thread_name) {
+ return rtc::scoped_ptr<ThreadWrapper>(
+ new ThreadType(func, obj, thread_name)).Pass();
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/thread_posix.cc b/webrtc/system_wrappers/source/thread_posix.cc
new file mode 100644
index 0000000000..32ab13c780
--- /dev/null
+++ b/webrtc/system_wrappers/source/thread_posix.cc
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/thread_posix.h"
+
+#include <algorithm>
+
+#include <errno.h>
+#include <unistd.h>
+#ifdef WEBRTC_LINUX
+#include <linux/unistd.h>
+#include <sched.h>
+#include <sys/types.h>
+#endif
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/platform_thread.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/include/event_wrapper.h"
+#include "webrtc/system_wrappers/include/sleep.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+namespace {
+struct ThreadAttributes {
+ ThreadAttributes() { pthread_attr_init(&attr); }
+ ~ThreadAttributes() { pthread_attr_destroy(&attr); }
+ pthread_attr_t* operator&() { return &attr; }
+ pthread_attr_t attr;
+};
+} // namespace
+
+int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
+ int max_prio) {
+ RTC_DCHECK(max_prio - min_prio > 2);
+ const int top_prio = max_prio - 1;
+ const int low_prio = min_prio + 1;
+
+ switch (priority) {
+ case kLowPriority:
+ return low_prio;
+ case kNormalPriority:
+ // The -1 ensures that the kHighPriority is always greater or equal to
+ // kNormalPriority.
+ return (low_prio + top_prio - 1) / 2;
+ case kHighPriority:
+ return std::max(top_prio - 2, low_prio);
+ case kHighestPriority:
+ return std::max(top_prio - 1, low_prio);
+ case kRealtimePriority:
+ return top_prio;
+ }
+ RTC_DCHECK(false);
+ return low_prio;
+}
+
+// static
+void* ThreadPosix::StartThread(void* param) {
+ static_cast<ThreadPosix*>(param)->Run();
+ return 0;
+}
+
+ThreadPosix::ThreadPosix(ThreadRunFunction func, void* obj,
+ const char* thread_name)
+ : run_function_(func),
+ obj_(obj),
+ stop_event_(false, false),
+ name_(thread_name ? thread_name : "webrtc"),
+ thread_(0) {
+ RTC_DCHECK(name_.length() < 64);
+}
+
+uint32_t ThreadWrapper::GetThreadId() {
+ return rtc::CurrentThreadId();
+}
+
+ThreadPosix::~ThreadPosix() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+// TODO(pbos): Make Start void, calling code really doesn't support failures
+// here.
+bool ThreadPosix::Start() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(!thread_) << "Thread already started?";
+
+ ThreadAttributes attr;
+ // Set the stack stack size to 1M.
+ pthread_attr_setstacksize(&attr, 1024 * 1024);
+ RTC_CHECK_EQ(0, pthread_create(&thread_, &attr, &StartThread, this));
+ return true;
+}
+
+bool ThreadPosix::Stop() {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ if (!thread_)
+ return true;
+
+ stop_event_.Set();
+ RTC_CHECK_EQ(0, pthread_join(thread_, nullptr));
+ thread_ = 0;
+
+ return true;
+}
+
+bool ThreadPosix::SetPriority(ThreadPriority priority) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ if (!thread_)
+ return false;
+#if defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
+ // TODO(tommi): Switch to the same mechanism as Chromium uses for
+ // changing thread priorities.
+ return true;
+#else
+#ifdef WEBRTC_THREAD_RR
+ const int policy = SCHED_RR;
+#else
+ const int policy = SCHED_FIFO;
+#endif
+ const int min_prio = sched_get_priority_min(policy);
+ const int max_prio = sched_get_priority_max(policy);
+ if (min_prio == -1 || max_prio == -1) {
+ WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
+ "unable to retreive min or max priority for threads");
+ return false;
+ }
+
+ if (max_prio - min_prio <= 2)
+ return false;
+
+ sched_param param;
+ param.sched_priority = ConvertToSystemPriority(priority, min_prio, max_prio);
+ if (pthread_setschedparam(thread_, policy, &param) != 0) {
+ WEBRTC_TRACE(
+ kTraceError, kTraceUtility, -1, "unable to set thread priority");
+ return false;
+ }
+
+ return true;
+#endif // defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_LINUX)
+}
+
+void ThreadPosix::Run() {
+ if (!name_.empty()) {
+ // Setting the thread name may fail (harmlessly) if running inside a
+ // sandbox. Ignore failures if they happen.
+ rtc::SetCurrentThreadName(name_.substr(0, 63).c_str());
+ }
+
+ // It's a requirement that for successful thread creation that the run
+ // function be called at least once (see RunFunctionIsCalled unit test),
+ // so to fullfill that requirement, we use a |do| loop and not |while|.
+ do {
+ if (!run_function_(obj_))
+ break;
+ } while (!stop_event_.Wait(0));
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/thread_posix.h b/webrtc/system_wrappers/source/thread_posix.h
new file mode 100644
index 0000000000..bcdd732f86
--- /dev/null
+++ b/webrtc/system_wrappers/source/thread_posix.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 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_POSIX_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_
+
+#include "webrtc/base/event.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/thread_checker.h"
+#include "webrtc/system_wrappers/include/thread_wrapper.h"
+
+#include <pthread.h>
+
+namespace webrtc {
+
+int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
+ int max_prio);
+
+class ThreadPosix : public ThreadWrapper {
+ public:
+ ThreadPosix(ThreadRunFunction func, void* obj, const char* thread_name);
+ ~ThreadPosix() override;
+
+ // From ThreadWrapper.
+ bool Start() override;
+ bool Stop() override;
+
+ bool SetPriority(ThreadPriority priority) override;
+
+ private:
+ static void* StartThread(void* param);
+
+ void Run();
+
+ rtc::ThreadChecker thread_checker_;
+ ThreadRunFunction const run_function_;
+ void* const obj_;
+ rtc::Event stop_event_;
+ const std::string name_;
+
+ pthread_t thread_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_
diff --git a/webrtc/system_wrappers/source/thread_posix_unittest.cc b/webrtc/system_wrappers/source/thread_posix_unittest.cc
new file mode 100644
index 0000000000..edfb14502e
--- /dev/null
+++ b/webrtc/system_wrappers/source/thread_posix_unittest.cc
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/thread_posix.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ThreadTestPosix, PrioritySettings) {
+ // API assumes that max_prio - min_prio > 2. Test the extreme case.
+ const int kMinPrio = -1;
+ const int kMaxPrio = 2;
+
+ int last_priority = kMinPrio;
+ for (int priority = webrtc::kLowPriority;
+ priority <= webrtc::kRealtimePriority; ++priority) {
+ int system_priority = webrtc::ConvertToSystemPriority(
+ static_cast<webrtc::ThreadPriority>(priority), kMinPrio, kMaxPrio);
+ EXPECT_GT(system_priority, kMinPrio);
+ EXPECT_LT(system_priority, kMaxPrio);
+ EXPECT_GE(system_priority, last_priority);
+ last_priority = system_priority;
+ }
+}
diff --git a/webrtc/system_wrappers/source/thread_unittest.cc b/webrtc/system_wrappers/source/thread_unittest.cc
new file mode 100644
index 0000000000..c8e180ba32
--- /dev/null
+++ b/webrtc/system_wrappers/source/thread_unittest.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/thread_wrapper.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/sleep.h"
+
+namespace webrtc {
+
+// Function that does nothing, and reports success.
+bool NullRunFunction(void* obj) {
+ SleepMs(0); // Hand over timeslice, prevents busy looping.
+ return true;
+}
+
+TEST(ThreadTest, StartStop) {
+ rtc::scoped_ptr<ThreadWrapper> thread = ThreadWrapper::CreateThread(
+ &NullRunFunction, nullptr, "ThreadTest");
+ ASSERT_TRUE(thread->Start());
+ EXPECT_TRUE(thread->Stop());
+}
+
+// Function that sets a boolean.
+bool SetFlagRunFunction(void* obj) {
+ bool* obj_as_bool = static_cast<bool*>(obj);
+ *obj_as_bool = true;
+ SleepMs(0); // Hand over timeslice, prevents busy looping.
+ return true;
+}
+
+TEST(ThreadTest, RunFunctionIsCalled) {
+ bool flag = false;
+ rtc::scoped_ptr<ThreadWrapper> thread = ThreadWrapper::CreateThread(
+ &SetFlagRunFunction, &flag, "RunFunctionIsCalled");
+ ASSERT_TRUE(thread->Start());
+
+ // At this point, the flag may be either true or false.
+ EXPECT_TRUE(thread->Stop());
+
+ // We expect the thread to have run at least once.
+ EXPECT_TRUE(flag);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/thread_win.cc b/webrtc/system_wrappers/source/thread_win.cc
new file mode 100644
index 0000000000..c42196722e
--- /dev/null
+++ b/webrtc/system_wrappers/source/thread_win.cc
@@ -0,0 +1,107 @@
+/*
+ * 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 "webrtc/system_wrappers/source/thread_win.h"
+
+#include <process.h>
+#include <stdio.h>
+#include <windows.h>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/platform_thread.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+namespace {
+void CALLBACK RaiseFlag(ULONG_PTR param) {
+ *reinterpret_cast<bool*>(param) = true;
+}
+}
+
+ThreadWindows::ThreadWindows(ThreadRunFunction func, void* obj,
+ const char* thread_name)
+ : run_function_(func),
+ obj_(obj),
+ stop_(false),
+ thread_(NULL),
+ name_(thread_name ? thread_name : "webrtc") {
+ RTC_DCHECK(func);
+}
+
+ThreadWindows::~ThreadWindows() {
+ RTC_DCHECK(main_thread_.CalledOnValidThread());
+ RTC_DCHECK(!thread_);
+}
+
+// static
+uint32_t ThreadWrapper::GetThreadId() {
+ return GetCurrentThreadId();
+}
+
+// static
+DWORD WINAPI ThreadWindows::StartThread(void* param) {
+ static_cast<ThreadWindows*>(param)->Run();
+ return 0;
+}
+
+bool ThreadWindows::Start() {
+ RTC_DCHECK(main_thread_.CalledOnValidThread());
+ RTC_DCHECK(!thread_);
+
+ stop_ = false;
+
+ // See bug 2902 for background on STACK_SIZE_PARAM_IS_A_RESERVATION.
+ // Set the reserved stack stack size to 1M, which is the default on Windows
+ // and Linux.
+ DWORD thread_id;
+ thread_ = ::CreateThread(NULL, 1024 * 1024, &StartThread, this,
+ STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_id);
+ if (!thread_ ) {
+ RTC_DCHECK(false) << "CreateThread failed";
+ return false;
+ }
+
+ return true;
+}
+
+bool ThreadWindows::Stop() {
+ RTC_DCHECK(main_thread_.CalledOnValidThread());
+ if (thread_) {
+ // Set stop_ to |true| on the worker thread.
+ QueueUserAPC(&RaiseFlag, thread_, reinterpret_cast<ULONG_PTR>(&stop_));
+ WaitForSingleObject(thread_, INFINITE);
+ CloseHandle(thread_);
+ thread_ = nullptr;
+ }
+
+ return true;
+}
+
+bool ThreadWindows::SetPriority(ThreadPriority priority) {
+ RTC_DCHECK(main_thread_.CalledOnValidThread());
+ return thread_ && SetThreadPriority(thread_, priority);
+}
+
+void ThreadWindows::Run() {
+ if (!name_.empty())
+ rtc::SetCurrentThreadName(name_.c_str());
+
+ do {
+ // The interface contract of Start/Stop is that for a successfull call to
+ // Start, there should be at least one call to the run function. So we
+ // call the function before checking |stop_|.
+ if (!run_function_(obj_))
+ break;
+ // Alertable sleep to permit RaiseFlag to run and update |stop_|.
+ SleepEx(0, true);
+ } while (!stop_);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/thread_win.h b/webrtc/system_wrappers/source/thread_win.h
new file mode 100644
index 0000000000..34edd6d6c0
--- /dev/null
+++ b/webrtc/system_wrappers/source/thread_win.h
@@ -0,0 +1,48 @@
+/*
+ * 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_WIN_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
+
+#include "webrtc/system_wrappers/include/thread_wrapper.h"
+
+#include <windows.h>
+
+#include "webrtc/base/thread_checker.h"
+
+namespace webrtc {
+
+class ThreadWindows : public ThreadWrapper {
+ public:
+ ThreadWindows(ThreadRunFunction func, void* obj, const char* thread_name);
+ ~ThreadWindows() override;
+
+ bool Start() override;
+ bool Stop() override;
+
+ bool SetPriority(ThreadPriority priority) override;
+
+ protected:
+ void Run();
+
+ private:
+ static DWORD WINAPI StartThread(void* param);
+
+ ThreadRunFunction const run_function_;
+ void* const obj_;
+ bool stop_;
+ HANDLE thread_;
+ const std::string name_;
+ rtc::ThreadChecker main_thread_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
diff --git a/webrtc/system_wrappers/source/tick_util.cc b/webrtc/system_wrappers/source/tick_util.cc
new file mode 100644
index 0000000000..bc8fcfe91b
--- /dev/null
+++ b/webrtc/system_wrappers/source/tick_util.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/include/tick_util.h"
+
+#include <assert.h>
+
+namespace webrtc {
+
+bool TickTime::use_fake_clock_ = false;
+int64_t TickTime::fake_ticks_ = 0;
+
+void TickTime::UseFakeClock(int64_t start_millisecond) {
+ use_fake_clock_ = true;
+ fake_ticks_ = MillisecondsToTicks(start_millisecond);
+}
+
+void TickTime::AdvanceFakeClock(int64_t milliseconds) {
+ assert(use_fake_clock_);
+ fake_ticks_ += MillisecondsToTicks(milliseconds);
+}
+
+int64_t TickTime::QueryOsForTicks() {
+ TickTime result;
+#if _WIN32
+ // TODO(wu): Remove QueryPerformanceCounter implementation.
+#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 last_time_get_time = 0;
+ static volatile int64_t num_wrap_time_get_time = 0;
+ volatile LONG* last_time_get_time_ptr = &last_time_get_time;
+ DWORD now = timeGetTime();
+ // Atomically update the last gotten time
+ DWORD old = InterlockedExchange(last_time_get_time_ptr, 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) {
+ num_wrap_time_get_time++;
+ }
+ }
+ result.ticks_ = now + (num_wrap_time_get_time << 32);
+#endif
+#elif defined(WEBRTC_LINUX)
+ struct timespec ts;
+ // TODO(wu): Remove CLOCK_REALTIME implementation.
+#ifdef WEBRTC_CLOCK_TYPE_REALTIME
+ clock_gettime(CLOCK_REALTIME, &ts);
+#else
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
+ result.ticks_ = 1000000000LL * static_cast<int64_t>(ts.tv_sec) +
+ static_cast<int64_t>(ts.tv_nsec);
+#elif defined(WEBRTC_MAC)
+ static mach_timebase_info_data_t timebase;
+ if (timebase.denom == 0) {
+ // Get the timebase if this is the first time we run.
+ // Recommended by Apple's QA1398.
+ kern_return_t retval = mach_timebase_info(&timebase);
+ if (retval != KERN_SUCCESS) {
+ // TODO(wu): Implement RTC_CHECK for all the platforms. Then replace this
+ // with a RTC_CHECK_EQ(retval, KERN_SUCCESS);
+#ifndef WEBRTC_IOS
+ asm("int3");
+#else
+ __builtin_trap();
+#endif // WEBRTC_IOS
+ }
+ }
+ // Use timebase to convert absolute time tick units into nanoseconds.
+ result.ticks_ = mach_absolute_time() * timebase.numer / timebase.denom;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ result.ticks_ = 1000000LL * static_cast<int64_t>(tv.tv_sec) +
+ static_cast<int64_t>(tv.tv_usec);
+#endif
+ return result.ticks_;
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/timestamp_extrapolator.cc b/webrtc/system_wrappers/source/timestamp_extrapolator.cc
new file mode 100644
index 0000000000..c7ed856a54
--- /dev/null
+++ b/webrtc/system_wrappers/source/timestamp_extrapolator.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 "webrtc/system_wrappers/include/timestamp_extrapolator.h"
+
+#include <algorithm>
+
+namespace webrtc {
+
+TimestampExtrapolator::TimestampExtrapolator(int64_t start_ms)
+ : _rwLock(RWLockWrapper::CreateRWLock()),
+ _startMs(0),
+ _firstTimestamp(0),
+ _wrapArounds(0),
+ _prevUnwrappedTimestamp(-1),
+ _prevWrapTimestamp(-1),
+ _lambda(1),
+ _firstAfterReset(true),
+ _packetCount(0),
+ _startUpFilterDelayInPackets(2),
+ _detectorAccumulatorPos(0),
+ _detectorAccumulatorNeg(0),
+ _alarmThreshold(60e3),
+ _accDrift(6600), // in timestamp ticks, i.e. 15 ms
+ _accMaxError(7000),
+ _pP11(1e10) {
+ Reset(start_ms);
+}
+
+TimestampExtrapolator::~TimestampExtrapolator()
+{
+ delete _rwLock;
+}
+
+void TimestampExtrapolator::Reset(int64_t start_ms)
+{
+ WriteLockScoped wl(*_rwLock);
+ _startMs = start_ms;
+ _prevMs = _startMs;
+ _firstTimestamp = 0;
+ _w[0] = 90.0;
+ _w[1] = 0;
+ _pP[0][0] = 1;
+ _pP[1][1] = _pP11;
+ _pP[0][1] = _pP[1][0] = 0;
+ _firstAfterReset = true;
+ _prevUnwrappedTimestamp = -1;
+ _prevWrapTimestamp = -1;
+ _wrapArounds = 0;
+ _packetCount = 0;
+ _detectorAccumulatorPos = 0;
+ _detectorAccumulatorNeg = 0;
+}
+
+void
+TimestampExtrapolator::Update(int64_t tMs, uint32_t ts90khz)
+{
+
+ _rwLock->AcquireLockExclusive();
+ if (tMs - _prevMs > 10e3)
+ {
+ // Ten seconds without a complete frame.
+ // Reset the extrapolator
+ _rwLock->ReleaseLockExclusive();
+ Reset(tMs);
+ _rwLock->AcquireLockExclusive();
+ }
+ else
+ {
+ _prevMs = tMs;
+ }
+
+ // Remove offset to prevent badly scaled matrices
+ tMs -= _startMs;
+
+ CheckForWrapArounds(ts90khz);
+
+ int64_t unwrapped_ts90khz = static_cast<int64_t>(ts90khz) +
+ _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
+
+ if (_prevUnwrappedTimestamp >= 0 &&
+ unwrapped_ts90khz < _prevUnwrappedTimestamp)
+ {
+ // Drop reordered frames.
+ _rwLock->ReleaseLockExclusive();
+ return;
+ }
+
+ if (_firstAfterReset)
+ {
+ // Make an initial guess of the offset,
+ // should be almost correct since tMs - _startMs
+ // should about zero at this time.
+ _w[1] = -_w[0] * tMs;
+ _firstTimestamp = unwrapped_ts90khz;
+ _firstAfterReset = false;
+ }
+
+ double residual =
+ (static_cast<double>(unwrapped_ts90khz) - _firstTimestamp) -
+ static_cast<double>(tMs) * _w[0] - _w[1];
+ if (DelayChangeDetection(residual) &&
+ _packetCount >= _startUpFilterDelayInPackets)
+ {
+ // A sudden change of average network delay has been detected.
+ // Force the filter to adjust its offset parameter by changing
+ // the offset uncertainty. Don't do this during startup.
+ _pP[1][1] = _pP11;
+ }
+ //T = [t(k) 1]';
+ //that = T'*w;
+ //K = P*T/(lambda + T'*P*T);
+ double K[2];
+ K[0] = _pP[0][0] * tMs + _pP[0][1];
+ K[1] = _pP[1][0] * tMs + _pP[1][1];
+ double TPT = _lambda + tMs * K[0] + K[1];
+ K[0] /= TPT;
+ K[1] /= TPT;
+ //w = w + K*(ts(k) - that);
+ _w[0] = _w[0] + K[0] * residual;
+ _w[1] = _w[1] + K[1] * residual;
+ //P = 1/lambda*(P - K*T'*P);
+ double p00 = 1 / _lambda *
+ (_pP[0][0] - (K[0] * tMs * _pP[0][0] + K[0] * _pP[1][0]));
+ double p01 = 1 / _lambda *
+ (_pP[0][1] - (K[0] * tMs * _pP[0][1] + K[0] * _pP[1][1]));
+ _pP[1][0] = 1 / _lambda *
+ (_pP[1][0] - (K[1] * tMs * _pP[0][0] + K[1] * _pP[1][0]));
+ _pP[1][1] = 1 / _lambda *
+ (_pP[1][1] - (K[1] * tMs * _pP[0][1] + K[1] * _pP[1][1]));
+ _pP[0][0] = p00;
+ _pP[0][1] = p01;
+ _prevUnwrappedTimestamp = unwrapped_ts90khz;
+ if (_packetCount < _startUpFilterDelayInPackets)
+ {
+ _packetCount++;
+ }
+ _rwLock->ReleaseLockExclusive();
+}
+
+int64_t
+TimestampExtrapolator::ExtrapolateLocalTime(uint32_t timestamp90khz)
+{
+ ReadLockScoped rl(*_rwLock);
+ int64_t localTimeMs = 0;
+ CheckForWrapArounds(timestamp90khz);
+ double unwrapped_ts90khz = static_cast<double>(timestamp90khz) +
+ _wrapArounds * ((static_cast<int64_t>(1) << 32) - 1);
+ if (_packetCount == 0)
+ {
+ localTimeMs = -1;
+ }
+ else if (_packetCount < _startUpFilterDelayInPackets)
+ {
+ localTimeMs = _prevMs + static_cast<int64_t>(
+ static_cast<double>(unwrapped_ts90khz - _prevUnwrappedTimestamp) /
+ 90.0 + 0.5);
+ }
+ else
+ {
+ if (_w[0] < 1e-3)
+ {
+ localTimeMs = _startMs;
+ }
+ else
+ {
+ double timestampDiff = unwrapped_ts90khz -
+ static_cast<double>(_firstTimestamp);
+ localTimeMs = static_cast<int64_t>(
+ static_cast<double>(_startMs) + (timestampDiff - _w[1]) /
+ _w[0] + 0.5);
+ }
+ }
+ return localTimeMs;
+}
+
+// Investigates if the timestamp clock has overflowed since the last timestamp and
+// keeps track of the number of wrap arounds since reset.
+void
+TimestampExtrapolator::CheckForWrapArounds(uint32_t ts90khz)
+{
+ if (_prevWrapTimestamp == -1)
+ {
+ _prevWrapTimestamp = ts90khz;
+ return;
+ }
+ if (ts90khz < _prevWrapTimestamp)
+ {
+ // This difference will probably be less than -2^31 if we have had a wrap around
+ // (e.g. timestamp = 1, _previousTimestamp = 2^32 - 1). Since it is casted to a Word32,
+ // it should be positive.
+ if (static_cast<int32_t>(ts90khz - _prevWrapTimestamp) > 0)
+ {
+ // Forward wrap around
+ _wrapArounds++;
+ }
+ }
+ // This difference will probably be less than -2^31 if we have had a backward wrap around.
+ // Since it is casted to a Word32, it should be positive.
+ else if (static_cast<int32_t>(_prevWrapTimestamp - ts90khz) > 0)
+ {
+ // Backward wrap around
+ _wrapArounds--;
+ }
+ _prevWrapTimestamp = ts90khz;
+}
+
+bool
+TimestampExtrapolator::DelayChangeDetection(double error)
+{
+ // CUSUM detection of sudden delay changes
+ error = (error > 0) ? std::min(error, _accMaxError) :
+ std::max(error, -_accMaxError);
+ _detectorAccumulatorPos =
+ std::max(_detectorAccumulatorPos + error - _accDrift, (double)0);
+ _detectorAccumulatorNeg =
+ std::min(_detectorAccumulatorNeg + error + _accDrift, (double)0);
+ if (_detectorAccumulatorPos > _alarmThreshold || _detectorAccumulatorNeg < -_alarmThreshold)
+ {
+ // Alarm
+ _detectorAccumulatorPos = _detectorAccumulatorNeg = 0;
+ return true;
+ }
+ return false;
+}
+
+}
diff --git a/webrtc/system_wrappers/source/trace_impl.cc b/webrtc/system_wrappers/source/trace_impl.cc
new file mode 100644
index 0000000000..ffe79b9862
--- /dev/null
+++ b/webrtc/system_wrappers/source/trace_impl.cc
@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/trace_impl.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "webrtc/base/atomicops.h"
+#ifdef _WIN32
+#include "webrtc/system_wrappers/source/trace_win.h"
+#else
+#include "webrtc/system_wrappers/source/trace_posix.h"
+#endif // _WIN32
+
+#define KEY_LEN_CHARS 31
+
+#ifdef _WIN32
+#pragma warning(disable:4355)
+#endif // _WIN32
+
+namespace webrtc {
+
+const int Trace::kBoilerplateLength = 71;
+const int Trace::kTimestampPosition = 13;
+const int Trace::kTimestampLength = 12;
+volatile int Trace::level_filter_ = kTraceDefault;
+
+// Construct On First Use idiom. Avoids "static initialization order fiasco".
+TraceImpl* TraceImpl::StaticInstance(CountOperation count_operation,
+ const TraceLevel level) {
+ // Sanities to avoid taking lock unless absolutely necessary (for
+ // performance reasons). count_operation == kAddRefNoCreate implies that a
+ // message will be written to file.
+ if ((level != kTraceAll) && (count_operation == kAddRefNoCreate)) {
+ if (!(level & level_filter())) {
+ return NULL;
+ }
+ }
+ TraceImpl* impl =
+ GetStaticInstance<TraceImpl>(count_operation);
+ return impl;
+}
+
+TraceImpl* TraceImpl::GetTrace(const TraceLevel level) {
+ return StaticInstance(kAddRefNoCreate, level);
+}
+
+TraceImpl* TraceImpl::CreateInstance() {
+#if defined(_WIN32)
+ return new TraceWindows();
+#else
+ return new TracePosix();
+#endif
+}
+
+TraceImpl::TraceImpl()
+ : callback_(NULL),
+ row_count_text_(0),
+ file_count_text_(0),
+ trace_file_(FileWrapper::Create()) {
+}
+
+TraceImpl::~TraceImpl() {
+ trace_file_->Flush();
+ trace_file_->CloseFile();
+}
+
+int32_t TraceImpl::AddThreadId(char* trace_message) const {
+ uint32_t thread_id = ThreadWrapper::GetThreadId();
+ // Messages is 12 characters.
+ return sprintf(trace_message, "%10u; ", thread_id);
+}
+
+int32_t TraceImpl::AddLevel(char* sz_message, const TraceLevel level) const {
+ const int kMessageLength = 12;
+ switch (level) {
+ case kTraceTerseInfo:
+ // Add the appropriate amount of whitespace.
+ memset(sz_message, ' ', kMessageLength);
+ sz_message[kMessageLength] = '\0';
+ break;
+ case kTraceStateInfo:
+ sprintf(sz_message, "STATEINFO ; ");
+ break;
+ case kTraceWarning:
+ sprintf(sz_message, "WARNING ; ");
+ break;
+ case kTraceError:
+ sprintf(sz_message, "ERROR ; ");
+ break;
+ case kTraceCritical:
+ sprintf(sz_message, "CRITICAL ; ");
+ break;
+ case kTraceInfo:
+ sprintf(sz_message, "DEBUGINFO ; ");
+ break;
+ case kTraceModuleCall:
+ sprintf(sz_message, "MODULECALL; ");
+ break;
+ case kTraceMemory:
+ sprintf(sz_message, "MEMORY ; ");
+ break;
+ case kTraceTimer:
+ sprintf(sz_message, "TIMER ; ");
+ break;
+ case kTraceStream:
+ sprintf(sz_message, "STREAM ; ");
+ break;
+ case kTraceApiCall:
+ sprintf(sz_message, "APICALL ; ");
+ break;
+ case kTraceDebug:
+ sprintf(sz_message, "DEBUG ; ");
+ break;
+ default:
+ assert(false);
+ return 0;
+ }
+ // All messages are 12 characters.
+ return kMessageLength;
+}
+
+int32_t TraceImpl::AddModuleAndId(char* trace_message,
+ const TraceModule module,
+ const int32_t id) const {
+ // Use long int to prevent problems with different definitions of
+ // int32_t.
+ // TODO(hellner): is this actually a problem? If so, it should be better to
+ // clean up int32_t
+ const long int idl = id;
+ const int kMessageLength = 25;
+ if (idl != -1) {
+ const unsigned long int id_engine = id >> 16;
+ const unsigned long int id_channel = id & 0xffff;
+
+ switch (module) {
+ case kTraceUndefined:
+ // Add the appropriate amount of whitespace.
+ memset(trace_message, ' ', kMessageLength);
+ trace_message[kMessageLength] = '\0';
+ break;
+ case kTraceVoice:
+ sprintf(trace_message, " VOICE:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceVideo:
+ sprintf(trace_message, " VIDEO:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceUtility:
+ sprintf(trace_message, " UTILITY:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceRtpRtcp:
+ sprintf(trace_message, " RTP/RTCP:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceTransport:
+ sprintf(trace_message, " TRANSPORT:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceAudioCoding:
+ sprintf(trace_message, "AUDIO CODING:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceSrtp:
+ sprintf(trace_message, " SRTP:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceAudioMixerServer:
+ sprintf(trace_message, " AUDIO MIX/S:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceAudioMixerClient:
+ sprintf(trace_message, " AUDIO MIX/C:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceVideoCoding:
+ sprintf(trace_message, "VIDEO CODING:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceVideoMixer:
+ // Print sleep time and API call
+ sprintf(trace_message, " VIDEO MIX:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceFile:
+ sprintf(trace_message, " FILE:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceAudioProcessing:
+ sprintf(trace_message, " AUDIO PROC:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceAudioDevice:
+ sprintf(trace_message, "AUDIO DEVICE:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceVideoRenderer:
+ sprintf(trace_message, "VIDEO RENDER:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceVideoCapture:
+ sprintf(trace_message, "VIDEO CAPTUR:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ case kTraceRemoteBitrateEstimator:
+ sprintf(trace_message, " BWE RBE:%5ld %5ld;", id_engine,
+ id_channel);
+ break;
+ }
+ } else {
+ switch (module) {
+ case kTraceUndefined:
+ // Add the appropriate amount of whitespace.
+ memset(trace_message, ' ', kMessageLength);
+ trace_message[kMessageLength] = '\0';
+ break;
+ case kTraceVoice:
+ sprintf(trace_message, " VOICE:%11ld;", idl);
+ break;
+ case kTraceVideo:
+ sprintf(trace_message, " VIDEO:%11ld;", idl);
+ break;
+ case kTraceUtility:
+ sprintf(trace_message, " UTILITY:%11ld;", idl);
+ break;
+ case kTraceRtpRtcp:
+ sprintf(trace_message, " RTP/RTCP:%11ld;", idl);
+ break;
+ case kTraceTransport:
+ sprintf(trace_message, " TRANSPORT:%11ld;", idl);
+ break;
+ case kTraceAudioCoding:
+ sprintf(trace_message, "AUDIO CODING:%11ld;", idl);
+ break;
+ case kTraceSrtp:
+ sprintf(trace_message, " SRTP:%11ld;", idl);
+ break;
+ case kTraceAudioMixerServer:
+ sprintf(trace_message, " AUDIO MIX/S:%11ld;", idl);
+ break;
+ case kTraceAudioMixerClient:
+ sprintf(trace_message, " AUDIO MIX/C:%11ld;", idl);
+ break;
+ case kTraceVideoCoding:
+ sprintf(trace_message, "VIDEO CODING:%11ld;", idl);
+ break;
+ case kTraceVideoMixer:
+ sprintf(trace_message, " VIDEO MIX:%11ld;", idl);
+ break;
+ case kTraceFile:
+ sprintf(trace_message, " FILE:%11ld;", idl);
+ break;
+ case kTraceAudioProcessing:
+ sprintf(trace_message, " AUDIO PROC:%11ld;", idl);
+ break;
+ case kTraceAudioDevice:
+ sprintf(trace_message, "AUDIO DEVICE:%11ld;", idl);
+ break;
+ case kTraceVideoRenderer:
+ sprintf(trace_message, "VIDEO RENDER:%11ld;", idl);
+ break;
+ case kTraceVideoCapture:
+ sprintf(trace_message, "VIDEO CAPTUR:%11ld;", idl);
+ break;
+ case kTraceRemoteBitrateEstimator:
+ sprintf(trace_message, " BWE RBE:%11ld;", idl);
+ break;
+ }
+ }
+ return kMessageLength;
+}
+
+int32_t TraceImpl::SetTraceFileImpl(const char* file_name_utf8,
+ const bool add_file_counter) {
+ rtc::CritScope lock(&crit_);
+
+ trace_file_->Flush();
+ trace_file_->CloseFile();
+
+ if (file_name_utf8) {
+ if (add_file_counter) {
+ file_count_text_ = 1;
+
+ char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize];
+ CreateFileName(file_name_utf8, file_name_with_counter_utf8,
+ file_count_text_);
+ if (trace_file_->OpenFile(file_name_with_counter_utf8, false, false,
+ true) == -1) {
+ return -1;
+ }
+ } else {
+ file_count_text_ = 0;
+ if (trace_file_->OpenFile(file_name_utf8, false, false, true) == -1) {
+ return -1;
+ }
+ }
+ }
+ row_count_text_ = 0;
+ return 0;
+}
+
+int32_t TraceImpl::TraceFileImpl(
+ char file_name_utf8[FileWrapper::kMaxFileNameSize]) {
+ rtc::CritScope lock(&crit_);
+ return trace_file_->FileName(file_name_utf8, FileWrapper::kMaxFileNameSize);
+}
+
+int32_t TraceImpl::SetTraceCallbackImpl(TraceCallback* callback) {
+ rtc::CritScope lock(&crit_);
+ callback_ = callback;
+ return 0;
+}
+
+int32_t TraceImpl::AddMessage(
+ char* trace_message,
+ const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
+ const uint16_t written_so_far) const {
+ int length = 0;
+ if (written_so_far >= WEBRTC_TRACE_MAX_MESSAGE_SIZE) {
+ return -1;
+ }
+ // - 2 to leave room for newline and NULL termination.
+#ifdef _WIN32
+ length = _snprintf(trace_message,
+ WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
+ "%s", msg);
+ if (length < 0) {
+ length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
+ trace_message[length] = 0;
+ }
+#else
+ length = snprintf(trace_message,
+ WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2,
+ "%s", msg);
+ if (length < 0 ||
+ length > WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2) {
+ length = WEBRTC_TRACE_MAX_MESSAGE_SIZE - written_so_far - 2;
+ trace_message[length] = 0;
+ }
+#endif
+ // Length with NULL termination.
+ return length + 1;
+}
+
+void TraceImpl::AddMessageToList(
+ const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
+ const uint16_t length,
+ const TraceLevel level) {
+ rtc::CritScope lock(&crit_);
+ if (callback_)
+ callback_->Print(level, trace_message, length);
+ WriteToFile(trace_message, length);
+}
+
+void TraceImpl::WriteToFile(const char* msg, uint16_t length) {
+ if (!trace_file_->Open())
+ return;
+
+ if (row_count_text_ > WEBRTC_TRACE_MAX_FILE_SIZE) {
+ // wrap file
+ row_count_text_ = 0;
+ trace_file_->Flush();
+
+ if (file_count_text_ == 0) {
+ trace_file_->Rewind();
+ } else {
+ char old_file_name[FileWrapper::kMaxFileNameSize];
+ char new_file_name[FileWrapper::kMaxFileNameSize];
+
+ // get current name
+ trace_file_->FileName(old_file_name, FileWrapper::kMaxFileNameSize);
+ trace_file_->CloseFile();
+
+ file_count_text_++;
+
+ UpdateFileName(old_file_name, new_file_name, file_count_text_);
+
+ if (trace_file_->OpenFile(new_file_name, false, false, true) == -1) {
+ return;
+ }
+ }
+ }
+ if (row_count_text_ == 0) {
+ char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1];
+ int32_t length = AddDateTimeInfo(message);
+ if (length != -1) {
+ message[length] = 0;
+ message[length - 1] = '\n';
+ trace_file_->Write(message, length);
+ row_count_text_++;
+ }
+ }
+
+ char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
+ memcpy(trace_message, msg, length);
+ trace_message[length] = 0;
+ trace_message[length - 1] = '\n';
+ trace_file_->Write(trace_message, length);
+ row_count_text_++;
+}
+
+void TraceImpl::AddImpl(const TraceLevel level,
+ const TraceModule module,
+ const int32_t id,
+ const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE]) {
+ if (!TraceCheck(level))
+ return;
+
+ char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
+ char* message_ptr = &trace_message[0];
+ int32_t len = AddLevel(message_ptr, level);
+ if (len == -1)
+ return;
+
+ message_ptr += len;
+ int32_t ack_len = len;
+
+ len = AddTime(message_ptr, level);
+ if (len == -1)
+ return;
+
+ message_ptr += len;
+ ack_len += len;
+
+ len = AddModuleAndId(message_ptr, module, id);
+ if (len == -1)
+ return;
+
+ message_ptr += len;
+ ack_len += len;
+
+ len = AddThreadId(message_ptr);
+ if (len < 0)
+ return;
+
+ message_ptr += len;
+ ack_len += len;
+
+ len = AddMessage(message_ptr, msg, static_cast<uint16_t>(ack_len));
+ if (len == -1)
+ return;
+
+ ack_len += len;
+ AddMessageToList(trace_message, static_cast<uint16_t>(ack_len), level);
+}
+
+bool TraceImpl::TraceCheck(const TraceLevel level) const {
+ return (level & level_filter()) ? true : false;
+}
+
+bool TraceImpl::UpdateFileName(
+ const char file_name_utf8[FileWrapper::kMaxFileNameSize],
+ char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
+ const uint32_t new_count) const {
+ int32_t length = (int32_t)strlen(file_name_utf8);
+ if (length < 0) {
+ return false;
+ }
+
+ int32_t length_without_file_ending = length - 1;
+ while (length_without_file_ending > 0) {
+ if (file_name_utf8[length_without_file_ending] == '.') {
+ break;
+ } else {
+ length_without_file_ending--;
+ }
+ }
+ if (length_without_file_ending == 0) {
+ length_without_file_ending = length;
+ }
+ int32_t length_to_ = length_without_file_ending - 1;
+ while (length_to_ > 0) {
+ if (file_name_utf8[length_to_] == '_') {
+ break;
+ } else {
+ length_to_--;
+ }
+ }
+
+ memcpy(file_name_with_counter_utf8, file_name_utf8, length_to_);
+ sprintf(file_name_with_counter_utf8 + length_to_, "_%lu%s",
+ static_cast<long unsigned int>(new_count),
+ file_name_utf8 + length_without_file_ending);
+ return true;
+}
+
+bool TraceImpl::CreateFileName(
+ const char file_name_utf8[FileWrapper::kMaxFileNameSize],
+ char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
+ const uint32_t new_count) const {
+ int32_t length = (int32_t)strlen(file_name_utf8);
+ if (length < 0) {
+ return false;
+ }
+
+ int32_t length_without_file_ending = length - 1;
+ while (length_without_file_ending > 0) {
+ if (file_name_utf8[length_without_file_ending] == '.') {
+ break;
+ } else {
+ length_without_file_ending--;
+ }
+ }
+ if (length_without_file_ending == 0) {
+ length_without_file_ending = length;
+ }
+ memcpy(file_name_with_counter_utf8, file_name_utf8,
+ length_without_file_ending);
+ sprintf(file_name_with_counter_utf8 + length_without_file_ending, "_%lu%s",
+ static_cast<long unsigned int>(new_count),
+ file_name_utf8 + length_without_file_ending);
+ return true;
+}
+
+// static
+void Trace::CreateTrace() {
+ TraceImpl::StaticInstance(kAddRef);
+}
+
+// static
+void Trace::ReturnTrace() {
+ TraceImpl::StaticInstance(kRelease);
+}
+
+// static
+int32_t Trace::TraceFile(char file_name[FileWrapper::kMaxFileNameSize]) {
+ TraceImpl* trace = TraceImpl::GetTrace();
+ if (trace) {
+ int ret_val = trace->TraceFileImpl(file_name);
+ ReturnTrace();
+ return ret_val;
+ }
+ return -1;
+}
+
+// static
+void Trace::set_level_filter(int filter) {
+ rtc::AtomicOps::ReleaseStore(&level_filter_, filter);
+}
+
+// static
+int Trace::level_filter() {
+ return rtc::AtomicOps::AcquireLoad(&level_filter_);
+}
+
+// static
+int32_t Trace::SetTraceFile(const char* file_name,
+ const bool add_file_counter) {
+ TraceImpl* trace = TraceImpl::GetTrace();
+ if (trace) {
+ int ret_val = trace->SetTraceFileImpl(file_name, add_file_counter);
+ ReturnTrace();
+ return ret_val;
+ }
+ return -1;
+}
+
+int32_t Trace::SetTraceCallback(TraceCallback* callback) {
+ TraceImpl* trace = TraceImpl::GetTrace();
+ if (trace) {
+ int ret_val = trace->SetTraceCallbackImpl(callback);
+ ReturnTrace();
+ return ret_val;
+ }
+ return -1;
+}
+
+void Trace::Add(const TraceLevel level, const TraceModule module,
+ const int32_t id, const char* msg, ...) {
+ TraceImpl* trace = TraceImpl::GetTrace(level);
+ if (trace) {
+ if (trace->TraceCheck(level)) {
+ char temp_buff[WEBRTC_TRACE_MAX_MESSAGE_SIZE];
+ char* buff = 0;
+ if (msg) {
+ va_list args;
+ va_start(args, msg);
+#ifdef _WIN32
+ _vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
+#else
+ vsnprintf(temp_buff, WEBRTC_TRACE_MAX_MESSAGE_SIZE - 1, msg, args);
+#endif
+ va_end(args);
+ buff = temp_buff;
+ }
+ trace->AddImpl(level, module, id, buff);
+ }
+ ReturnTrace();
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/trace_impl.h b/webrtc/system_wrappers/source/trace_impl.h
new file mode 100644
index 0000000000..ed49d9d0aa
--- /dev/null
+++ b/webrtc/system_wrappers/source/trace_impl.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/base/criticalsection.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/event_wrapper.h"
+#include "webrtc/system_wrappers/include/file_wrapper.h"
+#include "webrtc/system_wrappers/include/static_instance.h"
+#include "webrtc/system_wrappers/include/thread_wrapper.h"
+#include "webrtc/system_wrappers/include/trace.h"
+
+namespace webrtc {
+
+#define WEBRTC_TRACE_MAX_MESSAGE_SIZE 1024
+// 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 TraceImpl* CreateInstance();
+ static TraceImpl* GetTrace(const TraceLevel level = kTraceAll);
+
+ int32_t SetTraceFileImpl(const char* file_name, const bool add_file_counter);
+ int32_t TraceFileImpl(char file_name[FileWrapper::kMaxFileNameSize]);
+
+ int32_t SetTraceCallbackImpl(TraceCallback* callback);
+
+ void AddImpl(const TraceLevel level, const TraceModule module,
+ const int32_t id, const char* msg);
+
+ bool TraceCheck(const TraceLevel level) const;
+
+ protected:
+ TraceImpl();
+
+ static TraceImpl* StaticInstance(CountOperation count_operation,
+ const TraceLevel level = kTraceAll);
+
+ int32_t AddThreadId(char* trace_message) const;
+
+ // OS specific implementations.
+ virtual int32_t AddTime(char* trace_message,
+ const TraceLevel level) const = 0;
+
+ virtual int32_t AddDateTimeInfo(char* trace_message) const = 0;
+
+ private:
+ friend class Trace;
+
+ int32_t AddLevel(char* sz_message, const TraceLevel level) const;
+
+ int32_t AddModuleAndId(char* trace_message, const TraceModule module,
+ const int32_t id) const;
+
+ int32_t AddMessage(char* trace_message,
+ const char msg[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
+ const uint16_t written_so_far) const;
+
+ void AddMessageToList(
+ const char trace_message[WEBRTC_TRACE_MAX_MESSAGE_SIZE],
+ const uint16_t length,
+ const TraceLevel level);
+
+ bool UpdateFileName(
+ const char file_name_utf8[FileWrapper::kMaxFileNameSize],
+ char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
+ const uint32_t new_count) const;
+
+ bool CreateFileName(
+ const char file_name_utf8[FileWrapper::kMaxFileNameSize],
+ char file_name_with_counter_utf8[FileWrapper::kMaxFileNameSize],
+ const uint32_t new_count) const;
+
+ void WriteToFile(const char* msg, uint16_t length)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_);
+
+ TraceCallback* callback_ GUARDED_BY(crit_);
+ uint32_t row_count_text_ GUARDED_BY(crit_);
+ uint32_t file_count_text_ GUARDED_BY(crit_);
+
+ const rtc::scoped_ptr<FileWrapper> trace_file_ GUARDED_BY(crit_);
+ rtc::CriticalSection crit_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_IMPL_H_
diff --git a/webrtc/system_wrappers/source/trace_posix.cc b/webrtc/system_wrappers/source/trace_posix.cc
new file mode 100644
index 0000000000..cb702d8cea
--- /dev/null
+++ b/webrtc/system_wrappers/source/trace_posix.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/trace_posix.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+namespace webrtc {
+
+TracePosix::TracePosix()
+ : crit_sect_(*CriticalSectionWrapper::CreateCriticalSection()) {
+ struct timeval system_time_high_res;
+ gettimeofday(&system_time_high_res, 0);
+ prev_api_tick_count_ = prev_tick_count_ = system_time_high_res.tv_sec;
+}
+
+TracePosix::~TracePosix() {
+ delete &crit_sect_;
+}
+
+int32_t TracePosix::AddTime(char* trace_message, const TraceLevel level) const {
+ struct timeval system_time_high_res;
+ if (gettimeofday(&system_time_high_res, 0) == -1) {
+ return -1;
+ }
+ struct tm buffer;
+ const struct tm* system_time =
+ localtime_r(&system_time_high_res.tv_sec, &buffer);
+
+ const uint32_t ms_time = system_time_high_res.tv_usec / 1000;
+ uint32_t prev_tickCount = 0;
+ {
+ CriticalSectionScoped lock(&crit_sect_);
+ if (level == kTraceApiCall) {
+ prev_tickCount = prev_tick_count_;
+ prev_tick_count_ = ms_time;
+ } else {
+ prev_tickCount = prev_api_tick_count_;
+ prev_api_tick_count_ = ms_time;
+ }
+ }
+
+ uint32_t dw_delta_time = ms_time - prev_tickCount;
+ if (prev_tickCount == 0) {
+ dw_delta_time = 0;
+ }
+ if (dw_delta_time > 0x0fffffff) {
+ // Either wraparound or data race.
+ dw_delta_time = 0;
+ }
+ if (dw_delta_time > 99999) {
+ dw_delta_time = 99999;
+ }
+
+ sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5lu) ", system_time->tm_hour,
+ system_time->tm_min, system_time->tm_sec, ms_time,
+ static_cast<unsigned long>(dw_delta_time));
+ // Messages are 22 characters.
+ return 22;
+}
+
+int32_t TracePosix::AddDateTimeInfo(char* trace_message) const {
+ time_t t;
+ time(&t);
+ char buffer[26]; // man ctime says buffer should have room for >=26 bytes.
+ sprintf(trace_message, "Local Date: %s", ctime_r(&t, buffer));
+ int32_t len = static_cast<int32_t>(strlen(trace_message));
+
+ if ('\n' == trace_message[len - 1]) {
+ trace_message[len - 1] = '\0';
+ --len;
+ }
+
+ // Messages is 12 characters.
+ return len + 1;
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/trace_posix.h b/webrtc/system_wrappers/source/trace_posix.h
new file mode 100644
index 0000000000..25dfeec079
--- /dev/null
+++ b/webrtc/system_wrappers/source/trace_posix.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_TRACE_POSIX_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_
+
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/source/trace_impl.h"
+
+namespace webrtc {
+
+class TracePosix : public TraceImpl {
+ public:
+ TracePosix();
+ ~TracePosix() override;
+
+ // This method can be called on several different threads different from
+ // the creating thread.
+ int32_t AddTime(char* trace_message, const TraceLevel level) const override;
+
+ int32_t AddDateTimeInfo(char* trace_message) const override;
+
+ private:
+ volatile mutable uint32_t prev_api_tick_count_;
+ volatile mutable uint32_t prev_tick_count_;
+
+ CriticalSectionWrapper& crit_sect_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_POSIX_H_
diff --git a/webrtc/system_wrappers/source/trace_win.cc b/webrtc/system_wrappers/source/trace_win.cc
new file mode 100644
index 0000000000..4caedfce77
--- /dev/null
+++ b/webrtc/system_wrappers/source/trace_win.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012 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 "webrtc/system_wrappers/source/trace_win.h"
+
+#include <assert.h>
+#include <stdarg.h>
+
+#include "Mmsystem.h"
+
+namespace webrtc {
+TraceWindows::TraceWindows()
+ : prev_api_tick_count_(0),
+ prev_tick_count_(0) {
+}
+
+TraceWindows::~TraceWindows() {
+}
+
+int32_t TraceWindows::AddTime(char* trace_message,
+ const TraceLevel level) const {
+ uint32_t dw_current_time = timeGetTime();
+ SYSTEMTIME system_time;
+ GetSystemTime(&system_time);
+
+ if (level == kTraceApiCall) {
+ uint32_t dw_delta_time = dw_current_time - prev_tick_count_;
+ prev_tick_count_ = dw_current_time;
+
+ if (prev_tick_count_ == 0) {
+ dw_delta_time = 0;
+ }
+ if (dw_delta_time > 0x0fffffff) {
+ // Either wrap-around or data race.
+ dw_delta_time = 0;
+ }
+ if (dw_delta_time > 99999) {
+ dw_delta_time = 99999;
+ }
+
+ sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5u) ", system_time.wHour,
+ system_time.wMinute, system_time.wSecond,
+ system_time.wMilliseconds, dw_delta_time);
+ } else {
+ uint32_t dw_delta_time = dw_current_time - prev_api_tick_count_;
+ prev_api_tick_count_ = dw_current_time;
+
+ if (prev_api_tick_count_ == 0) {
+ dw_delta_time = 0;
+ }
+ if (dw_delta_time > 0x0fffffff) {
+ // Either wraparound or data race.
+ dw_delta_time = 0;
+ }
+ if (dw_delta_time > 99999) {
+ dw_delta_time = 99999;
+ }
+ sprintf(trace_message, "(%2u:%2u:%2u:%3u |%5u) ", system_time.wHour,
+ system_time.wMinute, system_time.wSecond,
+ system_time.wMilliseconds, dw_delta_time);
+ }
+ return 22;
+}
+
+int32_t TraceWindows::AddDateTimeInfo(char* trace_message) const {
+ prev_api_tick_count_ = timeGetTime();
+ prev_tick_count_ = prev_api_tick_count_;
+
+ SYSTEMTIME sys_time;
+ GetLocalTime(&sys_time);
+
+ TCHAR sz_date_str[20];
+ TCHAR sz_time_str[20];
+
+ // Create date string (e.g. Apr 04 2002)
+ GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &sys_time, TEXT("MMM dd yyyy"),
+ sz_date_str, 20);
+
+ // Create time string (e.g. 15:32:08)
+ GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &sys_time, TEXT("HH':'mm':'ss"),
+ sz_time_str, 20);
+
+ sprintf(trace_message, "Local Date: %ls Local Time: %ls", sz_date_str,
+ sz_time_str);
+
+ // Include NULL termination (hence + 1).
+ return static_cast<int32_t>(strlen(trace_message) + 1);
+}
+
+} // namespace webrtc
diff --git a/webrtc/system_wrappers/source/trace_win.h b/webrtc/system_wrappers/source/trace_win.h
new file mode 100644
index 0000000000..1311b23c57
--- /dev/null
+++ b/webrtc/system_wrappers/source/trace_win.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_TRACE_WIN_H_
+#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_
+
+#include <stdio.h>
+#include <windows.h>
+
+#include "webrtc/system_wrappers/source/trace_impl.h"
+
+namespace webrtc {
+
+class TraceWindows : public TraceImpl {
+ public:
+ TraceWindows();
+ virtual ~TraceWindows();
+
+ virtual int32_t AddTime(char* trace_message, const TraceLevel level) const;
+
+ virtual int32_t AddDateTimeInfo(char* trace_message) const;
+ private:
+ volatile mutable uint32_t prev_api_tick_count_;
+ volatile mutable uint32_t prev_tick_count_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WIN_H_