diff options
Diffstat (limited to 'src/system_wrappers')
59 files changed, 3916 insertions, 951 deletions
diff --git a/src/system_wrappers/interface/atomic32.h b/src/system_wrappers/interface/atomic32.h new file mode 100644 index 0000000000..e2b12589d7 --- /dev/null +++ b/src/system_wrappers/interface/atomic32.h @@ -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. + */ + +// Atomic, system independent 32-bit integer. Unless you know what you're +// doing, use locks instead! :-) +// +// Note: uses full memory barriers. +// Note: assumes 32-bit (or higher) system +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ + +#include <cstddef> + +#include "common_types.h" +#include "constructor_magic.h" + +namespace webrtc { + +// 32 bit atomic variable. Note that this class relies on the compiler to +// align the 32 bit value correctly (on a 32 bit boundary), so as long as you're +// not doing things like reinterpret_cast over some custom allocated memory +// without being careful with alignment, you should be fine. +class Atomic32 +{ +public: + Atomic32(WebRtc_Word32 initialValue = 0); + ~Atomic32(); + + // Prefix operator! + WebRtc_Word32 operator++(); + WebRtc_Word32 operator--(); + + WebRtc_Word32 operator+=(WebRtc_Word32 value); + WebRtc_Word32 operator-=(WebRtc_Word32 value); + + // Sets the value atomically to newValue if the value equals compare value. + // The function returns true if the exchange happened. + bool CompareExchange(WebRtc_Word32 newValue, WebRtc_Word32 compareValue); + WebRtc_Word32 Value() const; + +private: + // Disable the + and - operator since it's unclear what these operations + // should do. + Atomic32 operator+(const Atomic32& other); + Atomic32 operator-(const Atomic32& other); + + // Checks if |_value| is 32bit aligned. + inline bool Is32bitAligned() const { + return (reinterpret_cast<ptrdiff_t>(&_value) & 3) == 0; + } + + DISALLOW_COPY_AND_ASSIGN(Atomic32); + + WebRtc_Word32 _value; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ diff --git a/src/system_wrappers/interface/atomic32_wrapper.h b/src/system_wrappers/interface/atomic32_wrapper.h deleted file mode 100644 index 40862fb492..0000000000 --- a/src/system_wrappers/interface/atomic32_wrapper.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Atomic system independant 32-bit integer. -// Note: uses full memory barriers. -// Note: assumes 32-bit (or higher) system -#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ -#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ - -#include "common_types.h" - -namespace webrtc { -class Atomic32Impl; -class Atomic32Wrapper -{ -public: - Atomic32Wrapper(WebRtc_Word32 initialValue = 0); - ~Atomic32Wrapper(); - - // Prefix operator! - WebRtc_Word32 operator++(); - WebRtc_Word32 operator--(); - - Atomic32Wrapper& operator=(const Atomic32Wrapper& rhs); - Atomic32Wrapper& operator=(WebRtc_Word32 rhs); - - WebRtc_Word32 operator+=(WebRtc_Word32 rhs); - WebRtc_Word32 operator-=(WebRtc_Word32 rhs); - - // Sets the value atomically to newValue if the value equals compare value. - // The function returns true if the exchange happened. - bool CompareExchange(WebRtc_Word32 newValue, WebRtc_Word32 compareValue); - WebRtc_Word32 Value() const; -private: - // Disable the + and - operator since it's unclear what these operations - // should do. - Atomic32Wrapper operator+(const Atomic32Wrapper& rhs); - Atomic32Wrapper operator-(const Atomic32Wrapper& rhs); - - WebRtc_Word32& operator++(int); - WebRtc_Word32& operator--(int); - - // Cheshire cat to hide the implementation (faster than - // using virtual functions) - Atomic32Impl& _impl; -}; -} // namespace webrtc -#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ diff --git a/src/system_wrappers/interface/compile_assert.h b/src/system_wrappers/interface/compile_assert.h new file mode 100644 index 0000000000..4feda86c3a --- /dev/null +++ b/src/system_wrappers/interface/compile_assert.h @@ -0,0 +1,21 @@ +/* + * 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_INTERFACE_COMPILE_ASSERT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ + +/* Use this macro to verify at compile time that certain restrictions are met. + * The argument is the boolean expression to evaluate. + * Example: + * COMPILE_ASSERT(sizeof(foo) < 128); +*/ +#define COMPILE_ASSERT(expression) switch(0){case 0: case expression:;} + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ diff --git a/src/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h b/src/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h new file mode 100644 index 0000000000..d85c724729 --- /dev/null +++ b/src/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h @@ -0,0 +1,35 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file under third_party_mods/chromium directory of +// source tree or at +// http://src.chromium.org/viewvc/chrome/trunk/src/LICENSE + +// Various inline functions and macros to fix compilation of 32 bit target +// on MSVC with /Wp64 flag enabled. + +// The original code can be found here: +// http://src.chromium.org/svn/trunk/src/base/fix_wp64.h + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ + +#include <windows.h> + +// Platform SDK fixes when building with /Wp64 for a 32 bits target. +#if !defined(_WIN64) && defined(_Wp64) + +#ifdef InterlockedExchangePointer +#undef InterlockedExchangePointer +// The problem is that the macro provided for InterlockedExchangePointer() is +// doing a (LONG) C-style cast that triggers invariably the warning C4312 when +// building on 32 bits. +inline void* InterlockedExchangePointer(void* volatile* target, void* value) { + return reinterpret_cast<void*>(static_cast<LONG_PTR>(InterlockedExchange( + reinterpret_cast<volatile LONG*>(target), + static_cast<LONG>(reinterpret_cast<LONG_PTR>(value))))); +} +#endif // #ifdef InterlockedExchangePointer + +#endif // #if !defined(_WIN64) && defined(_Wp64) + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ diff --git a/src/system_wrappers/interface/ref_count.h b/src/system_wrappers/interface/ref_count.h index f90b0b3609..5112bd9037 100644 --- a/src/system_wrappers/interface/ref_count.h +++ b/src/system_wrappers/interface/ref_count.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -11,7 +11,7 @@ #ifndef SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_ #define SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_ -#include "system_wrappers/interface/atomic32_wrapper.h" +#include "system_wrappers/interface/atomic32.h" namespace webrtc { @@ -74,7 +74,7 @@ class RefCountImpl : public T { } protected: - Atomic32Wrapper ref_count_; + Atomic32 ref_count_; }; } // namespace webrtc diff --git a/src/system_wrappers/interface/sleep.h b/src/system_wrappers/interface/sleep.h new file mode 100644 index 0000000000..c0205bf085 --- /dev/null +++ b/src/system_wrappers/interface/sleep.h @@ -0,0 +1,24 @@ +/* + * 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. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ + +namespace webrtc { + +// This function sleeps for the specified number of milliseconds. +// It may return early if the thread is woken by some other event, +// such as the delivery of a signal on Unix. +void SleepMs(int msecs); + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ diff --git a/src/system_wrappers/interface/static_instance.h b/src/system_wrappers/interface/static_instance.h index 8fe91cc3e4..b670f969c9 100644 --- a/src/system_wrappers/interface/static_instance.h +++ b/src/system_wrappers/interface/static_instance.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -128,10 +128,8 @@ static T* GetStaticInstance(CountOperation count_operation) { // local copy. T* new_instance = T::CreateInstance(); if (1 == InterlockedIncrement(&instance_count)) { - T* old_value = static_cast<T*> (InterlockedExchangePointer( - reinterpret_cast<void* volatile*>(&instance), new_instance)); - assert(old_value == NULL); - assert(instance); + InterlockedExchangePointer(reinterpret_cast<void* volatile*>(&instance), + new_instance); } else { InterlockedDecrement(&instance_count); if (new_instance) { diff --git a/src/system_wrappers/interface/thread_wrapper.h b/src/system_wrappers/interface/thread_wrapper.h index 72a06e8bdd..030ac8a6f7 100644 --- a/src/system_wrappers/interface/thread_wrapper.h +++ b/src/system_wrappers/interface/thread_wrapper.h @@ -16,6 +16,9 @@ #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ +#include "common_types.h" +#include "typedefs.h" + namespace webrtc { // Object that will be passed by the spawned thread when it enters the callback // function. @@ -51,9 +54,12 @@ public: // threadName NULL terminated thread name, will be visable in the Windows // debugger. static ThreadWrapper* CreateThread(ThreadRunFunction func = 0, - ThreadObj obj= 0, - ThreadPriority prio = kNormalPriority, - const char* threadName = 0); + ThreadObj obj= 0, + ThreadPriority prio = kNormalPriority, + const char* threadName = 0); + + // Get the current thread's kernel thread ID. + static uint32_t GetThreadId(); // Non blocking termination of the spawned thread. Note that it is not safe // to delete this class until the spawned thread has been reclaimed. @@ -69,8 +75,9 @@ public: // should be lower than (number of CPUs - 1). amountOfProcessors should be // equal to the number of processors listed in processorNumbers virtual bool SetAffinity(const int* /*processorNumbers*/, - const unsigned int /*amountOfProcessors*/) - {return false;} + const unsigned int /*amountOfProcessors*/) { + return false; + } // Stops the spawned thread and waits for it to be reclaimed with a timeout // of two seconds. Will return false if the thread was not reclaimed. diff --git a/src/system_wrappers/interface/tick_util.h b/src/system_wrappers/interface/tick_util.h index e78e53d2e1..0cd85d0050 100644 --- a/src/system_wrappers/interface/tick_util.h +++ b/src/system_wrappers/interface/tick_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -19,6 +19,9 @@ #include <mmsystem.h> #elif WEBRTC_LINUX #include <ctime> +#elif WEBRTC_MAC +#include <mach/mach_time.h> +#include <string.h> #else #include <sys/time.h> #include <time.h> @@ -133,6 +136,7 @@ inline TickTime TickTime::Now() { 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 @@ -164,12 +168,27 @@ inline TickTime TickTime::Now() #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<WebRtc_Word64>(ts.tv_sec) + static_cast<WebRtc_Word64>(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 CHECK similar to chrome for all the platforms. + // Then replace this with a CHECK(retval == KERN_SUCCESS); + asm("int3"); + } + } + // 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); @@ -189,7 +208,7 @@ inline WebRtc_Word64 TickTime::MillisecondTimestamp() #else return now._ticks; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return now._ticks / 1000000LL; #else return now._ticks / 1000LL; @@ -208,7 +227,7 @@ inline WebRtc_Word64 TickTime::MicrosecondTimestamp() #else return now._ticks *1000LL; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return now._ticks / 1000LL; #else return now._ticks; @@ -230,7 +249,7 @@ inline WebRtc_Word64 TickTime::MillisecondsToTicks(const WebRtc_Word64 ms) #else return ms; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return ms * 1000000LL; #else return ms * 1000LL; @@ -247,7 +266,7 @@ inline WebRtc_Word64 TickTime::TicksToMilliseconds(const WebRtc_Word64 ticks) #else return ticks; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return ticks / 1000000LL; #else return ticks / 1000LL; @@ -280,7 +299,7 @@ inline WebRtc_Word64 TickInterval::Milliseconds() const // _interval is in ms return _interval; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) // _interval is in ns return _interval / 1000000; #else @@ -300,7 +319,7 @@ inline WebRtc_Word64 TickInterval::Microseconds() const // _interval is in ms return _interval *1000LL; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) // _interval is in ns return _interval / 1000; #else diff --git a/src/system_wrappers/interface/trace.h b/src/system_wrappers/interface/trace.h index 8330f7c4e1..f88d23f8a7 100644 --- a/src/system_wrappers/interface/trace.h +++ b/src/system_wrappers/interface/trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -45,11 +45,11 @@ public: // Sets the file name. If addFileCounter is false the same file will be // reused when it fills up. If it's true a new file with incremented name // will be used. - static WebRtc_Word32 SetTraceFile(const WebRtc_Word8* fileName, + static WebRtc_Word32 SetTraceFile(const char* fileName, const bool addFileCounter = false); // Returns the name of the file that the trace is currently writing to. - static WebRtc_Word32 TraceFile(WebRtc_Word8 fileName[1024]); + static WebRtc_Word32 TraceFile(char fileName[1024]); // Registers callback to receive trace messages. TODO (hellner) // why not use OutStream instead? Why is TraceCallback not defined in this @@ -70,7 +70,6 @@ public: const TraceModule module, const WebRtc_Word32 id, const char* msg, ...); - }; } // namespace webrtc #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ diff --git a/src/system_wrappers/source/Android.mk b/src/system_wrappers/source/Android.mk index 575580a497..dee84ca294 100644 --- a/src/system_wrappers/source/Android.mk +++ b/src/system_wrappers/source/Android.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +# 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 @@ -17,15 +17,15 @@ LOCAL_MODULE := libwebrtc_system_wrappers LOCAL_MODULE_TAGS := optional LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := \ + android/cpu-features.c \ + cpu_features_android.c \ map.cc \ - rw_lock_generic.cc \ sort.cc \ aligned_malloc.cc \ - atomic32.cc \ + atomic32_posix.cc \ condition_variable.cc \ cpu_no_op.cc \ cpu_features.cc \ - cpu_features_arm.c \ cpu_info.cc \ critical_section.cc \ event.cc \ @@ -38,6 +38,7 @@ LOCAL_SRC_FILES := \ cpu_linux.cc \ critical_section_posix.cc \ event_posix.cc \ + sleep.cc \ thread_posix.cc \ trace_posix.cc \ rw_lock_posix.cc diff --git a/src/system_wrappers/source/android/cpu-features.c b/src/system_wrappers/source/android/cpu-features.c new file mode 100644 index 0000000000..6a5cd8f1aa --- /dev/null +++ b/src/system_wrappers/source/android/cpu-features.c @@ -0,0 +1,396 @@ +/* + * 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 <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/src/system_wrappers/source/android/cpu-features.h b/src/system_wrappers/source/android/cpu-features.h new file mode 100644 index 0000000000..f20c0bc4d9 --- /dev/null +++ b/src/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/src/system_wrappers/source/atomic32.cc b/src/system_wrappers/source/atomic32.cc deleted file mode 100644 index 588dd3e07d..0000000000 --- a/src/system_wrappers/source/atomic32.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "atomic32_wrapper.h" - -#if defined(_WIN32) - #include "atomic32_win.h" -#elif defined(WEBRTC_LINUX) - #include "atomic32_linux.h" -#elif defined(WEBRTC_MAC) - #include "atomic32_mac.h" -#else - #error unsupported os! -#endif - -namespace webrtc { -Atomic32Wrapper::Atomic32Wrapper(WebRtc_Word32 initialValue) - : _impl(*new Atomic32Impl(initialValue)) -{ -} - -Atomic32Wrapper::~Atomic32Wrapper() -{ - delete &_impl; -} - -WebRtc_Word32 Atomic32Wrapper::operator++() -{ - return ++_impl; -} - -WebRtc_Word32 Atomic32Wrapper::operator--() -{ - return --_impl; -} - -// Read and write to properly aligned variables are atomic operations. -// Ex reference (for Windows): http://msdn.microsoft.com/en-us/library/ms684122(v=VS.85).aspx -// TODO (hellner) operator= and Atomic32Wrapper::Value() can be fully -// implemented here. -Atomic32Wrapper& Atomic32Wrapper::operator=(const Atomic32Wrapper& rhs) -{ - if(this == &rhs) - { - return *this; - } - _impl = rhs._impl; - return *this; -} - -Atomic32Wrapper& Atomic32Wrapper::operator=(WebRtc_Word32 rhs) -{ - _impl = rhs; - return *this; -} - -WebRtc_Word32 Atomic32Wrapper::operator+=(WebRtc_Word32 rhs) -{ - return _impl += rhs; -} - -WebRtc_Word32 Atomic32Wrapper::operator-=(WebRtc_Word32 rhs) -{ - return _impl -= rhs; -} - -bool Atomic32Wrapper::CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue) -{ - return _impl.CompareExchange(newValue,compareValue); -} - -WebRtc_Word32 Atomic32Wrapper::Value() const -{ - return _impl.Value(); -} -} // namespace webrtc diff --git a/src/system_wrappers/source/atomic32_linux.h b/src/system_wrappers/source/atomic32_linux.h deleted file mode 100644 index f9f5650f2a..0000000000 --- a/src/system_wrappers/source/atomic32_linux.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Atomic system independant 32-bit signed integer. -// Linux implementation. -// Note: Requires gcc 4.1.2 or later. -#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ -#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ - -#include <inttypes.h> -#include <malloc.h> - -#include "common_types.h" - -namespace webrtc { -class Atomic32Impl -{ -public: - inline Atomic32Impl(WebRtc_Word32 initialValue); - inline ~Atomic32Impl(); - - inline WebRtc_Word32 operator++(); - inline WebRtc_Word32 operator--(); - - inline Atomic32Impl& operator=(const Atomic32Impl& rhs); - inline Atomic32Impl& operator=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator+=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator-=(WebRtc_Word32 rhs); - - inline bool CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue); - - inline WebRtc_Word32 Value() const; -private: - void* _ptrMemory; - // Volatile ensures full memory barriers. - volatile WebRtc_Word32* _value; -}; - -// TODO (hellner) use aligned_malloc instead of doing it manually. -inline Atomic32Impl::Atomic32Impl(WebRtc_Word32 initialValue) - : _ptrMemory(NULL), - _value(NULL) -{ // Align the memory associated with _value on a 32-bit boundary. This is a - // requirement for the used Linux APIs to be atomic. - // Keep _ptrMemory to be able to reclaim memory. - _ptrMemory = malloc(sizeof(WebRtc_Word32)*2); - _value = (WebRtc_Word32*) (((uintptr_t)_ptrMemory+3)&(~0x3)); - *_value = initialValue; -} - -inline Atomic32Impl::~Atomic32Impl() -{ - if(_ptrMemory != NULL) - { - free(_ptrMemory); - } -} - -inline WebRtc_Word32 Atomic32Impl::operator++() -{ - WebRtc_Word32 returnValue = __sync_fetch_and_add(_value,1); - returnValue++; - return returnValue; -} - -inline WebRtc_Word32 Atomic32Impl::operator--() -{ - WebRtc_Word32 returnValue = __sync_fetch_and_sub(_value,1); - returnValue--; - return returnValue; -} - -inline Atomic32Impl& Atomic32Impl::operator=(const Atomic32Impl& rhs) -{ - *_value = *rhs._value; - return *this; -} - -inline Atomic32Impl& Atomic32Impl::operator=(WebRtc_Word32 rhs) -{ - *_value = rhs; - return *this; -} - -inline WebRtc_Word32 Atomic32Impl::operator+=(WebRtc_Word32 rhs) -{ - WebRtc_Word32 returnValue = __sync_fetch_and_add(_value,rhs); - returnValue += rhs; - return returnValue; -} - -inline WebRtc_Word32 Atomic32Impl::operator-=(WebRtc_Word32 rhs) -{ - WebRtc_Word32 returnValue = __sync_fetch_and_sub(_value,rhs); - returnValue -= rhs; - return returnValue; -} - -inline bool Atomic32Impl::CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue) -{ - return __sync_bool_compare_and_swap(_value,compareValue,newValue); -} - -inline WebRtc_Word32 Atomic32Impl::Value() const -{ - return *_value; -} -} // namespace webrtc - -#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ diff --git a/src/system_wrappers/source/atomic32_mac.cc b/src/system_wrappers/source/atomic32_mac.cc new file mode 100644 index 0000000000..9a493b580c --- /dev/null +++ b/src/system_wrappers/source/atomic32_mac.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 "atomic32.h" + +#include <assert.h> +#include <libkern/OSAtomic.h> +#include <stdlib.h> + +#include "common_types.h" + +namespace webrtc { + +Atomic32::Atomic32(WebRtc_Word32 initialValue) : _value(initialValue) +{ + assert(Is32bitAligned()); +} + +Atomic32::~Atomic32() +{ +} + +WebRtc_Word32 Atomic32::operator++() +{ + return OSAtomicIncrement32Barrier(&_value); +} + +WebRtc_Word32 Atomic32::operator--() +{ + return OSAtomicDecrement32Barrier(&_value); +} + +WebRtc_Word32 Atomic32::operator+=(WebRtc_Word32 value) +{ + return OSAtomicAdd32Barrier(value, &_value); +} + +WebRtc_Word32 Atomic32::operator-=(WebRtc_Word32 value) +{ + return OSAtomicAdd32Barrier(-value, &_value); +} + +bool Atomic32::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + return OSAtomicCompareAndSwap32Barrier(compareValue, newValue, &_value); +} + +WebRtc_Word32 Atomic32::Value() const +{ + return _value; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/atomic32_mac.h b/src/system_wrappers/source/atomic32_mac.h deleted file mode 100644 index bf8febcdb5..0000000000 --- a/src/system_wrappers/source/atomic32_mac.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -// Atomic system independant 32-bit signed integer. -// Mac implementation. -#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ -#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ - -#include <stdlib.h> -#include <libkern/OSAtomic.h> - -#include "common_types.h" - -namespace webrtc { -class Atomic32Impl -{ -public: - inline Atomic32Impl(WebRtc_Word32 initialValue); - inline ~Atomic32Impl(); - - inline WebRtc_Word32 operator++(); - inline WebRtc_Word32 operator--(); - - inline Atomic32Impl& operator=(const Atomic32Impl& rhs); - inline Atomic32Impl& operator=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator+=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator-=(WebRtc_Word32 rhs); - - inline bool CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue); - - inline WebRtc_Word32 Value() const; -private: - void* _ptrMemory; - // Volatile ensures full memory barriers. - volatile WebRtc_Word32* _value; -}; - -// TODO (hellner) use aligned_malloc instead of doing it manually. -inline Atomic32Impl::Atomic32Impl(WebRtc_Word32 initialValue) - : - _ptrMemory(NULL), - _value(NULL) -{ // Align the memory associated with _value on a 32-bit boundary. This is a - // requirement for the used Mac APIs to be atomic. - // Keep _ptrMemory to be able to reclaim memory. - _ptrMemory = malloc(sizeof(WebRtc_Word32)*2); - _value = (WebRtc_Word32*) (((uintptr_t)_ptrMemory+3)&(~0x3)); - *_value = initialValue; -} - -inline Atomic32Impl::~Atomic32Impl() -{ - if(_ptrMemory != NULL) - { - free(_ptrMemory); - } -} - -inline WebRtc_Word32 Atomic32Impl::operator++() -{ - return OSAtomicIncrement32Barrier( - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline WebRtc_Word32 Atomic32Impl::operator--() -{ - return OSAtomicDecrement32Barrier( - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline Atomic32Impl& Atomic32Impl::operator=(const Atomic32Impl& rhs) -{ - *_value = *rhs._value; - return *this; -} - -inline Atomic32Impl& Atomic32Impl::operator=(WebRtc_Word32 rhs) -{ - *_value = rhs; - return *this; -} - -inline WebRtc_Word32 Atomic32Impl::operator+=(WebRtc_Word32 rhs) -{ - return OSAtomicAdd32Barrier(rhs, - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline WebRtc_Word32 Atomic32Impl::operator-=(WebRtc_Word32 rhs) -{ - return OSAtomicAdd32Barrier(-rhs, - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline bool Atomic32Impl::CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue) -{ - return OSAtomicCompareAndSwap32Barrier( - compareValue, - newValue, - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline WebRtc_Word32 Atomic32Impl::Value() const -{ - return *_value; -} -} // namespace webrtc -#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ diff --git a/src/system_wrappers/source/atomic32_posix.cc b/src/system_wrappers/source/atomic32_posix.cc new file mode 100644 index 0000000000..05b0e57456 --- /dev/null +++ b/src/system_wrappers/source/atomic32_posix.cc @@ -0,0 +1,64 @@ +/* + * 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 "atomic32.h" + +#include <assert.h> +#include <inttypes.h> +#include <malloc.h> + +#include "common_types.h" + +namespace webrtc { + +Atomic32::Atomic32(WebRtc_Word32 initialValue) : _value(initialValue) +{ + assert(Is32bitAligned()); +} + +Atomic32::~Atomic32() +{ +} + +WebRtc_Word32 Atomic32::operator++() +{ + return __sync_fetch_and_add(&_value, 1) + 1; +} + +WebRtc_Word32 Atomic32::operator--() +{ + return __sync_fetch_and_sub(&_value, 1) - 1; +} + +WebRtc_Word32 Atomic32::operator+=(WebRtc_Word32 value) +{ + WebRtc_Word32 returnValue = __sync_fetch_and_add(&_value, value); + returnValue += value; + return returnValue; +} + +WebRtc_Word32 Atomic32::operator-=(WebRtc_Word32 value) +{ + WebRtc_Word32 returnValue = __sync_fetch_and_sub(&_value, value); + returnValue -= value; + return returnValue; +} + +bool Atomic32::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + return __sync_bool_compare_and_swap(&_value, compareValue, newValue); +} + +WebRtc_Word32 Atomic32::Value() const +{ + return _value; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/atomic32_win.cc b/src/system_wrappers/source/atomic32_win.cc new file mode 100644 index 0000000000..2fa9d3dd59 --- /dev/null +++ b/src/system_wrappers/source/atomic32_win.cc @@ -0,0 +1,72 @@ +/* + * 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 "atomic32.h" + +#include <assert.h> +#include <windows.h> + +#include "common_types.h" +#include "compile_assert.h" + +namespace webrtc { + +Atomic32::Atomic32(WebRtc_Word32 initialValue) : _value(initialValue) +{ + // Make sure that the counter variable we're using is of the same size + // as what the API expects. + COMPILE_ASSERT(sizeof(_value) == sizeof(LONG)); + assert(Is32bitAligned()); +} + +Atomic32::~Atomic32() +{ +} + +WebRtc_Word32 Atomic32::operator++() +{ + return static_cast<WebRtc_Word32>(InterlockedIncrement( + reinterpret_cast<volatile LONG*>(&_value))); +} + +WebRtc_Word32 Atomic32::operator--() +{ + return static_cast<WebRtc_Word32>(InterlockedDecrement( + reinterpret_cast<volatile LONG*>(&_value))); +} + +WebRtc_Word32 Atomic32::operator+=(WebRtc_Word32 value) +{ + return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&_value), + value); +} + +WebRtc_Word32 Atomic32::operator-=(WebRtc_Word32 value) +{ + return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&_value), + -value); +} + +bool Atomic32::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + const LONG oldValue = InterlockedCompareExchange( + reinterpret_cast<volatile LONG*>(&_value), + newValue, + compareValue); + // If the old value and the compare value is the same an exchange happened. + return (oldValue == compareValue); +} + +WebRtc_Word32 Atomic32::Value() const +{ + return _value; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/condition_variable_unittest.cc b/src/system_wrappers/source/condition_variable_unittest.cc new file mode 100644 index 0000000000..a9fdd0d24e --- /dev/null +++ b/src/system_wrappers/source/condition_variable_unittest.cc @@ -0,0 +1,208 @@ +/* + * 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 "system_wrappers/interface/condition_variable_wrapper.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/critical_section_wrapper.h" +#include "system_wrappers/interface/thread_wrapper.h" +#include "system_wrappers/interface/trace.h" +#include "system_wrappers/source/unittest_utilities.h" + +namespace webrtc { + +namespace { + +const int kLogTrace = false; // Set to true to enable debug logging to stdout. +const int kLongWaitMs = 100*1000; // A long time in testing terms +const int kShortWaitMs = 2*1000; // Long enough for process switches to happen + +#define LOG(...) WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, __VA_ARGS__); + +// 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(WebRtc_UWord32 max_msecs) { + LOG("Locking giver_sect"); + CriticalSectionScoped cs_giver(giver_sect_); + LOG("Locked giver_sect, locking crit_sect"); + CriticalSectionScoped cs(crit_sect_); + SignalBatonAvailable(); + const bool result = TakeBatonIfStillFree(max_msecs); + if (result) { + ++pass_count_; + LOG("Pass count is %d", pass_count_); + } + return result; + } + + // Grab the baton. Returns false if baton is not passed. + bool Grab(WebRtc_UWord32 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_) { + LOG("Wait waiting"); + if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) { + LOG("Wait timeout"); + return false; + } + } + being_passed_ = false; + cond_var_->Wake(); + return true; + } + + void SignalBatonAvailable() { + assert(!being_passed_); + being_passed_ = true; + LOG("Signal waking"); + 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) { + LOG("Takeback waiting"); + 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 { + LOG("Takeback grab"); + 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); + LOG("Thread waiting"); + EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); + LOG("Thread waking parent"); + EXPECT_TRUE(the_baton->Pass(kLongWaitMs)); + return true; +} + +class CondVarTest : public ::testing::Test { + public: + CondVarTest() + : trace_(kLogTrace) { + } + + virtual void SetUp() { + thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction, + &baton_); + unsigned int id = 42; + ASSERT_TRUE(thread_->Start(id)); + } + + 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)); + thread_->SetNotAlive(); + ASSERT_TRUE(baton_.Grab(kShortWaitMs)); + ASSERT_TRUE(thread_->Stop()); + delete thread_; + } + + protected: + Baton baton_; + + private: + ScopedTracing trace_; + ThreadWrapper* thread_; +}; + +// The SetUp and TearDown functions use condition variables. +// This test verifies those pieces in isolation. +TEST_F(CondVarTest, 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, 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()); +} + +} // anonymous namespace + +} // namespace webrtc diff --git a/src/system_wrappers/source/condition_variable_win.cc b/src/system_wrappers/source/condition_variable_win.cc new file mode 100644 index 0000000000..f4fae0b75f --- /dev/null +++ b/src/system_wrappers/source/condition_variable_win.cc @@ -0,0 +1,224 @@ +/* + * Use of this source code is governed by the ACE copyright license which + * can be found in the LICENSE file in the third_party_mods/ace directory of + * the source tree or at http://www1.cse.wustl.edu/~schmidt/ACE-copying.html. + */ +/* + * This source code contain modifications to the original source code + * which can be found here: + * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2). + * Modifications: + * 1) Dynamic detection of native support for condition variables. + * 2) Use of WebRTC defined types and classes. Renaming of some functions. + * 3) Introduction of a second event for wake all functionality. This prevents + * a thread from spinning on the same condition variable, preventing other + * threads from waking up. + */ + +// TODO (hellner): probably nicer to split up native and generic +// implementation into two different files + +#include "condition_variable_win.h" + +#include "critical_section_win.h" +#include "trace.h" + +namespace webrtc { +bool ConditionVariableWindows::_winSupportConditionVariablesPrimitive = false; +static HMODULE library = NULL; + +PInitializeConditionVariable _PInitializeConditionVariable; +PSleepConditionVariableCS _PSleepConditionVariableCS; +PWakeConditionVariable _PWakeConditionVariable; +PWakeAllConditionVariable _PWakeAllConditionVariable; + +typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); +typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, + PCRITICAL_SECTION, DWORD); +typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); +typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); + +ConditionVariableWindows::ConditionVariableWindows() + : _eventID(WAKEALL_0) +{ + if (!library) + { + // Use native implementation if supported (i.e Vista+) + library = LoadLibrary(TEXT("Kernel32.dll")); + if (library) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Kernel.dll"); + + _PInitializeConditionVariable = + (PInitializeConditionVariable) GetProcAddress( + library, + "InitializeConditionVariable"); + _PSleepConditionVariableCS = + (PSleepConditionVariableCS)GetProcAddress( + library, + "SleepConditionVariableCS"); + _PWakeConditionVariable = + (PWakeConditionVariable)GetProcAddress( + library, + "WakeConditionVariable"); + _PWakeAllConditionVariable = + (PWakeAllConditionVariable)GetProcAddress( + library, + "WakeAllConditionVariable"); + + if(_PInitializeConditionVariable && + _PSleepConditionVariableCS && + _PWakeConditionVariable && + _PWakeAllConditionVariable) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded native condition variables"); + _winSupportConditionVariablesPrimitive = true; + } + } + } + + if (_winSupportConditionVariablesPrimitive) + { + _PInitializeConditionVariable(&_conditionVariable); + + _events[WAKEALL_0] = NULL; + _events[WAKEALL_1] = NULL; + _events[WAKE] = NULL; + + } else { + memset(&_numWaiters[0],0,sizeof(_numWaiters)); + + InitializeCriticalSection(&_numWaitersCritSect); + + _events[WAKEALL_0] = CreateEvent(NULL, // no security attributes + TRUE, // manual-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + + _events[WAKEALL_1] = CreateEvent(NULL, // no security attributes + TRUE, // manual-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + + _events[WAKE] = CreateEvent(NULL, // no security attributes + FALSE, // auto-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + } +} + +ConditionVariableWindows::~ConditionVariableWindows() +{ + if(!_winSupportConditionVariablesPrimitive) + { + CloseHandle(_events[WAKE]); + CloseHandle(_events[WAKEALL_1]); + CloseHandle(_events[WAKEALL_0]); + + DeleteCriticalSection(&_numWaitersCritSect); + } +} + +void ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect) +{ + SleepCS(critSect, INFINITE); +} + +bool ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect, + unsigned long maxTimeInMS) +{ + CriticalSectionWindows* cs = reinterpret_cast<CriticalSectionWindows*>( + &critSect); + + if(_winSupportConditionVariablesPrimitive) + { + BOOL retVal = _PSleepConditionVariableCS(&_conditionVariable, + &(cs->crit),maxTimeInMS); + return (retVal == 0) ? false : true; + + }else + { + EnterCriticalSection(&_numWaitersCritSect); + // Get the eventID for the event that will be triggered by next + // WakeAll() call and start waiting for it. + const EventWakeUpType eventID = (WAKEALL_0 == _eventID) ? + WAKEALL_1 : WAKEALL_0; + ++(_numWaiters[eventID]); + LeaveCriticalSection(&_numWaitersCritSect); + + LeaveCriticalSection(&cs->crit); + HANDLE events[2]; + events[0] = _events[WAKE]; + events[1] = _events[eventID]; + const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events. + events, + FALSE, // Wait for either. + maxTimeInMS); + + const bool retVal = (result != WAIT_TIMEOUT); + + EnterCriticalSection(&_numWaitersCritSect); + --(_numWaiters[eventID]); + // Last waiter should only be true for WakeAll(). WakeAll() correspond + // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1) + const bool lastWaiter = (result == WAIT_OBJECT_0 + 1) && + (_numWaiters[eventID] == 0); + LeaveCriticalSection(&_numWaitersCritSect); + + if (lastWaiter) + { + // Reset/unset the WakeAll() event since all threads have been + // released. + ResetEvent(_events[eventID]); + } + + EnterCriticalSection(&cs->crit); + return retVal; + } +} + +void +ConditionVariableWindows::Wake() +{ + if(_winSupportConditionVariablesPrimitive) + { + _PWakeConditionVariable(&_conditionVariable); + }else + { + EnterCriticalSection(&_numWaitersCritSect); + const bool haveWaiters = (_numWaiters[WAKEALL_0] > 0) || + (_numWaiters[WAKEALL_1] > 0); + LeaveCriticalSection(&_numWaitersCritSect); + + if (haveWaiters) + { + SetEvent(_events[WAKE]); + } + } +} + +void +ConditionVariableWindows::WakeAll() +{ + if(_winSupportConditionVariablesPrimitive) + { + _PWakeAllConditionVariable(&_conditionVariable); + }else + { + EnterCriticalSection(&_numWaitersCritSect); + // Update current WakeAll() event + _eventID = (WAKEALL_0 == _eventID) ? WAKEALL_1 : WAKEALL_0; + // Trigger current event + const EventWakeUpType eventID = _eventID; + const bool haveWaiters = _numWaiters[eventID] > 0; + LeaveCriticalSection(&_numWaitersCritSect); + + if (haveWaiters) + { + SetEvent(_events[eventID]); + } + } +} +} // namespace webrtc diff --git a/src/system_wrappers/source/condition_variable_win.h b/src/system_wrappers/source/condition_variable_win.h new file mode 100644 index 0000000000..aab2564dd1 --- /dev/null +++ b/src/system_wrappers/source/condition_variable_win.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ + +#include "condition_variable_wrapper.h" + +#include <windows.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 ConditionVariableWindows : public ConditionVariableWrapper +{ +public: + ConditionVariableWindows(); + ~ConditionVariableWindows(); + + void SleepCS(CriticalSectionWrapper& critSect); + bool SleepCS(CriticalSectionWrapper& critSect, unsigned long maxTimeInMS); + void Wake(); + void WakeAll(); + +private: + enum EventWakeUpType + { + WAKEALL_0 = 0, + WAKEALL_1 = 1, + WAKE = 2, + EVENT_COUNT = 3 + }; + +private: + // Native support for Windows Vista+ + static bool _winSupportConditionVariablesPrimitive; + CONDITION_VARIABLE _conditionVariable; + + unsigned int _numWaiters[2]; + EventWakeUpType _eventID; + CRITICAL_SECTION _numWaitersCritSect; + HANDLE _events[EVENT_COUNT]; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ diff --git a/src/system_wrappers/source/cpu_features_android.c b/src/system_wrappers/source/cpu_features_android.c new file mode 100644 index 0000000000..7a4fa6ef20 --- /dev/null +++ b/src/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 "android/cpu-features.h" + +uint64_t WebRtc_GetCPUFeaturesARM(void) { + return android_getCpuFeatures(); +} diff --git a/src/system_wrappers/source/cpu_features_arm.c b/src/system_wrappers/source/cpu_features_arm.c deleted file mode 100644 index 106511852c..0000000000 --- a/src/system_wrappers/source/cpu_features_arm.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * 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 file is derived from Android's NDK package r7, located at -// <ndk>/sources/android/cpufeatures/ (downloadable from -// http://developer.android.com/sdk/ndk/index.html). - -#include "cpu_features_wrapper.h" - -#include <fcntl.h> -#include <errno.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> - -// Define CPU family. -typedef enum { - CPU_FAMILY_UNKNOWN = 0, - CPU_FAMILY_ARM, - CPU_FAMILY_X86, - CPU_FAMILY_MAX // Do not remove. -} CpuFamily; - -static pthread_once_t g_once; -static CpuFamily g_cpuFamily; -static uint64_t g_cpuFeatures; -static int g_cpuCount; - -static const int cpufeatures_debug = 0; - -#ifdef __arm__ -# define DEFAULT_CPU_FAMILY CPU_FAMILY_ARM -#elif defined __i386__ -# define DEFAULT_CPU_FAMILY CPU_FAMILY_X86 -#else -# define DEFAULT_CPU_FAMILY CPU_FAMILY_UNKNOWN -#endif - -#define D(...) \ - do { \ - if (cpufeatures_debug) { \ - printf(__VA_ARGS__); fflush(stdout); \ - } \ - } while (0) - -/* 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 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__ - { - 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! - * - * 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 |= kCPUFeatureARMv7; - } - - /* The LDREX / STREX instructions are available from ARMv6 */ - if (archNumber >= 6) { - g_cpuFeatures |= kCPUFeatureLDREXSTREX; - } - - 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 |= kCPUFeatureVFPv3; - - else if (has_list_item(cpuFeatures, "vfpv3d16")) - g_cpuFeatures |= kCPUFeatureVFPv3; - - 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 |= kCPUFeatureNEON | - kCPUFeatureVFPv3; - } - free(cpuFeatures); - } - } -#endif // __arm__ - -#ifdef __i386__ - g_cpuFamily = CPU_FAMILY_X86; -#endif -} - - -uint64_t WebRtc_GetCPUFeaturesARM(void) { - pthread_once(&g_once, cpuInit); - return g_cpuFeatures; -} diff --git a/src/system_wrappers/source/cpu_linux.cc b/src/system_wrappers/source/cpu_linux.cc index 9d7d89de64..8e8ecda6ca 100644 --- a/src/system_wrappers/source/cpu_linux.cc +++ b/src/system_wrappers/source/cpu_linux.cc @@ -179,6 +179,7 @@ int CpuLinux::GetNumCores() char line[100]; if (!fgets(line, 100, fp)) { + fclose(fp); return -1; } int numCores = -1; diff --git a/src/system_wrappers/source/cpu_measurement_harness.cc b/src/system_wrappers/source/cpu_measurement_harness.cc new file mode 100644 index 0000000000..237e776506 --- /dev/null +++ b/src/system_wrappers/source/cpu_measurement_harness.cc @@ -0,0 +1,127 @@ +/* + * 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 "system_wrappers/interface/cpu_wrapper.h" +#include "system_wrappers/interface/event_wrapper.h" +#include "system_wrappers/interface/scoped_ptr.h" +#include "system_wrappers/source/cpu_measurement_harness.h" + +const int kCpuCheckPeriodMs = 100; + +namespace webrtc { + +CpuMeasurementHarness* CpuMeasurementHarness::Create( + CpuTarget* target, + int work_period_ms, + int work_iterations_per_period, + int duration_ms) { + if (target == NULL) { + return NULL; + } + if (work_period_ms > duration_ms) { + return NULL; + } + if (work_period_ms < 0) { + return NULL; + } + if (duration_ms < 0) { + return NULL; + } + if (work_iterations_per_period < 1) { + return NULL; + } + return new CpuMeasurementHarness(target, work_period_ms, + work_iterations_per_period, duration_ms); +} + +CpuMeasurementHarness::CpuMeasurementHarness(CpuTarget* target, + int work_period_ms, + int work_iterations_per_period, + int duration_ms) + : cpu_target_(target), + work_period_ms_(work_period_ms), + work_iterations_per_period_(work_iterations_per_period), + duration_ms_(duration_ms), + cpu_sum_(0), + cpu_iterations_(0), + cpu_(CpuWrapper::CreateCpu()), + event_(EventWrapper::Create()) { +} + +CpuMeasurementHarness::~CpuMeasurementHarness() { +} + +bool CpuMeasurementHarness::Run() { + if (!WaitForCpuInit()) { + return false; + } + // No need for precision. Run for approximately the asked for duration. + // TODO(hellner): very low prio if at all, the actual duration of the test + // will be longer if calling DoWork() is not negligable and/or called many + // times. It may make sense to compensate for drift here. This will, + // however, only add complexity with minimal gains. Perhaps renaming the + // duration_ms_ to something more fuzzy is a better idea. However, the name + // would be very convoluted if it is to be self documenting. + int elapsed_time_ms = 0; + int last_measured_time = 0; + while (elapsed_time_ms < duration_ms_) { + if (((elapsed_time_ms - last_measured_time) / kCpuCheckPeriodMs) >= 1) { + last_measured_time = elapsed_time_ms; + Measure(); + } + if (!DoWork()) { + return false; + } + event_->Wait(work_period_ms_); + elapsed_time_ms += work_period_ms_; + } + return true; +} + +int CpuMeasurementHarness::AverageCpu() { + if (cpu_iterations_ == 0) { + return 0; + } + assert(cpu_sum_ >= 0); + assert(cpu_iterations_ >= 0); + return cpu_sum_ / cpu_iterations_; +} + +bool CpuMeasurementHarness::WaitForCpuInit() { + bool cpu_usage_available = false; + int num_iterations = 0; + // Initializing the CPU measurements may take a couple of seconds on Windows. + // Since the initialization is lazy we need to wait until it is completed. + // Should not take more than 10000 ms. + while (!cpu_usage_available && (++num_iterations < 10000)) { + event_->Wait(1); + cpu_usage_available = cpu_->CpuUsage() != -1; + } + return cpu_usage_available; +} + +void CpuMeasurementHarness::Measure() { + WebRtc_UWord32 num_cores = 0; + WebRtc_UWord32* cores = NULL; + // Return the average CPU for now. + cpu_sum_ = cpu_->CpuUsageMultiCore(num_cores, cores); + ++cpu_iterations_; +} + +bool CpuMeasurementHarness::DoWork() { + for (int i = 0; i < work_iterations_per_period_; ++i) { + if (!cpu_target_->DoWork()) { + return false; + } + } + return true; +} + +} // namespace webrtc diff --git a/src/system_wrappers/source/cpu_measurement_harness.h b/src/system_wrappers/source/cpu_measurement_harness.h new file mode 100644 index 0000000000..3b87f2775b --- /dev/null +++ b/src/system_wrappers/source/cpu_measurement_harness.h @@ -0,0 +1,66 @@ +/* + * 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 SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_ +#define SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_ + +#include "system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +class CpuWrapper; +class EventWrapper; +class ThreadWrapper; + +// This abstract class provides an interface that should be passed to +// CpuMeasurementHarness. CpuMeasurementHarness will call it with the +// frequency requested and measure the CPU usage for all calls. +class CpuTarget { + public: + // Callback function for which the CPU usage should be calculated. + virtual bool DoWork() = 0; + + protected: + CpuTarget() {} + virtual ~CpuTarget() {} +}; + +class CpuMeasurementHarness { + public: + static CpuMeasurementHarness* Create(CpuTarget* target, + int work_period_ms, + int work_iterations_per_period, + int duration_ms); + ~CpuMeasurementHarness(); + bool Run(); + int AverageCpu(); + + protected: + CpuMeasurementHarness(CpuTarget* target, int work_period_ms, + int work_iterations_per_period, int duration_ms); + + private: + bool WaitForCpuInit(); + void Measure(); + bool DoWork(); + + CpuTarget* cpu_target_; + const int work_period_ms_; + const int work_iterations_per_period_; + const int duration_ms_; + int cpu_sum_; + int cpu_iterations_; + scoped_ptr<CpuWrapper> cpu_; + scoped_ptr<EventWrapper> event_; +}; + +} // namespace webrtc + +#endif // SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_ diff --git a/src/system_wrappers/source/cpu_win.cc b/src/system_wrappers/source/cpu_win.cc new file mode 100644 index 0000000000..86a6a6ad38 --- /dev/null +++ b/src/system_wrappers/source/cpu_win.cc @@ -0,0 +1,530 @@ +/* + * 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_win.h" + +#define _WIN32_DCOM + +#include <assert.h> +#include <iostream> +#include <Wbemidl.h> + +#pragma comment(lib, "wbemuuid.lib") + +#include "condition_variable_wrapper.h" +#include "critical_section_wrapper.h" +#include "event_wrapper.h" +#include "thread_wrapper.h" + +namespace webrtc { +WebRtc_Word32 CpuWindows::CpuUsage() +{ + if (!has_initialized_) + { + return -1; + } + // Last element is the average + return cpu_usage_[number_of_objects_ - 1]; +} + +WebRtc_Word32 CpuWindows::CpuUsageMultiCore(WebRtc_UWord32& num_cores, + WebRtc_UWord32*& cpu_usage) +{ + if (has_terminated_) { + num_cores = 0; + cpu_usage = NULL; + return -1; + } + if (!has_initialized_) + { + num_cores = 0; + cpu_usage = NULL; + return -1; + } + num_cores = number_of_objects_ - 1; + cpu_usage = cpu_usage_; + return cpu_usage_[number_of_objects_-1]; +} + +CpuWindows::CpuWindows() + : cpu_polling_thread(NULL), + initialize_(true), + has_initialized_(false), + terminate_(false), + has_terminated_(false), + cpu_usage_(NULL), + wbem_enum_access_(NULL), + number_of_objects_(0), + cpu_usage_handle_(0), + previous_processor_timestamp_(NULL), + timestamp_sys_100_ns_handle_(0), + previous_100ns_timestamp_(NULL), + wbem_service_(NULL), + wbem_service_proxy_(NULL), + wbem_refresher_(NULL), + wbem_enum_(NULL) +{ + // All resources are allocated in PollingCpu(). + if (AllocateComplexDataTypes()) + { + StartPollingCpu(); + } + else + { + assert(false); + } +} + +CpuWindows::~CpuWindows() +{ + // All resources are reclaimed in StopPollingCpu(). + StopPollingCpu(); + DeAllocateComplexDataTypes(); +} + +bool CpuWindows::AllocateComplexDataTypes() +{ + cpu_polling_thread = ThreadWrapper::CreateThread( + CpuWindows::Process, + reinterpret_cast<void*>(this), + kNormalPriority, + "CpuWindows"); + init_crit_ = CriticalSectionWrapper::CreateCriticalSection(); + init_cond_ = ConditionVariableWrapper::CreateConditionVariable(); + terminate_crit_ = CriticalSectionWrapper::CreateCriticalSection(); + terminate_cond_ = ConditionVariableWrapper::CreateConditionVariable(); + sleep_event = EventWrapper::Create(); + return (cpu_polling_thread != NULL) && (init_crit_ != NULL) && + (init_cond_ != NULL) && (terminate_crit_ != NULL) && + (terminate_cond_ != NULL) && (sleep_event != NULL); +} + +void CpuWindows::DeAllocateComplexDataTypes() +{ + if (sleep_event != NULL) + { + delete sleep_event; + sleep_event = NULL; + } + if (terminate_cond_ != NULL) + { + delete terminate_cond_; + terminate_cond_ = NULL; + } + if (terminate_crit_ != NULL) + { + delete terminate_crit_; + terminate_crit_ = NULL; + } + if (init_cond_ != NULL) + { + delete init_cond_; + init_cond_ = NULL; + } + if (init_crit_ != NULL) + { + delete init_crit_; + init_crit_ = NULL; + } + if (cpu_polling_thread != NULL) + { + delete cpu_polling_thread; + cpu_polling_thread = NULL; + } +} + +void CpuWindows::StartPollingCpu() +{ + unsigned int dummy_id = 0; + if (!cpu_polling_thread->Start(dummy_id)) + { + initialize_ = false; + has_terminated_ = true; + assert(false); + } +} + +bool CpuWindows::StopPollingCpu() +{ + { + // If StopPollingCpu is called immediately after StartPollingCpu() it is + // possible that cpu_polling_thread is in the process of initializing. + // Let initialization finish to avoid getting into a bad state. + CriticalSectionScoped cs(init_crit_); + while(initialize_) + { + init_cond_->SleepCS(*init_crit_); + } + } + + CriticalSectionScoped cs(terminate_crit_); + terminate_ = true; + sleep_event->Set(); + while (!has_terminated_) + { + terminate_cond_->SleepCS(*terminate_crit_); + } + cpu_polling_thread->Stop(); + delete cpu_polling_thread; + cpu_polling_thread = NULL; + return true; +} + +bool CpuWindows::Process(void* thread_object) +{ + return reinterpret_cast<CpuWindows*>(thread_object)->ProcessImpl(); +} + +bool CpuWindows::ProcessImpl() +{ + { + CriticalSectionScoped cs(terminate_crit_); + if (terminate_) + { + Terminate(); + terminate_cond_->WakeAll(); + return false; + } + } + // Initialize on first iteration + if (initialize_) + { + CriticalSectionScoped cs(init_crit_); + initialize_ = false; + const bool success = Initialize(); + init_cond_->WakeAll(); + if (!success || !has_initialized_) + { + has_initialized_ = false; + terminate_ = true; + return true; + } + } + // Approximately one seconds sleep for each CPU measurement. Precision is + // not important. 1 second refresh rate is also used by Performance Monitor + // (perfmon). + if(kEventTimeout != sleep_event->Wait(1000)) + { + // Terminating. No need to update CPU usage. + assert(terminate_); + return true; + } + + // UpdateCpuUsage() returns false if a single (or more) CPU read(s) failed. + // Not a major problem if it happens. + UpdateCpuUsage(); + return true; +} + +bool CpuWindows::CreateWmiConnection() +{ + IWbemLocator* service_locator = NULL; + HRESULT hr = CoCreateInstance(CLSID_WbemLocator, NULL, + CLSCTX_INPROC_SERVER, IID_IWbemLocator, + reinterpret_cast<void**> (&service_locator)); + if (FAILED(hr)) + { + return false; + } + // To get the WMI service specify the WMI namespace. + BSTR wmi_namespace = SysAllocString(L"\\\\.\\root\\cimv2"); + if (wmi_namespace == NULL) + { + // This type of failure signifies running out of memory. + service_locator->Release(); + return false; + } + hr = service_locator->ConnectServer(wmi_namespace, NULL, NULL, NULL, 0L, + NULL, NULL, &wbem_service_); + SysFreeString(wmi_namespace); + service_locator->Release(); + return !FAILED(hr); +} + +// Sets up WMI refresher and enum +bool CpuWindows::CreatePerfOsRefresher() +{ + // Create refresher. + HRESULT hr = CoCreateInstance(CLSID_WbemRefresher, NULL, + CLSCTX_INPROC_SERVER, IID_IWbemRefresher, + reinterpret_cast<void**> (&wbem_refresher_)); + if (FAILED(hr)) + { + return false; + } + // Create PerfOS_Processor enum. + IWbemConfigureRefresher* wbem_refresher_config = NULL; + hr = wbem_refresher_->QueryInterface( + IID_IWbemConfigureRefresher, + reinterpret_cast<void**> (&wbem_refresher_config)); + if (FAILED(hr)) + { + return false; + } + + // Create a proxy to the IWbemServices so that a local authentication + // can be set up (this is needed to be able to successfully call + // IWbemConfigureRefresher::AddEnum). Setting authentication with + // CoInitializeSecurity is process-wide (which is too intrusive). + hr = CoCopyProxy(static_cast<IUnknown*> (wbem_service_), + reinterpret_cast<IUnknown**> (&wbem_service_proxy_)); + if(FAILED(hr)) + { + return false; + } + // Set local authentication. + // RPC_C_AUTHN_WINNT means using NTLM instead of Kerberos which is default. + hr = CoSetProxyBlanket(static_cast<IUnknown*> (wbem_service_proxy_), + RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); + if(FAILED(hr)) + { + return false; + } + + // Don't care about the particular id for the enum. + long enum_id = 0; + hr = wbem_refresher_config->AddEnum(wbem_service_proxy_, + L"Win32_PerfRawData_PerfOS_Processor", + 0, NULL, &wbem_enum_, &enum_id); + wbem_refresher_config->Release(); + wbem_refresher_config = NULL; + return !FAILED(hr); +} + +// Have to pull the first round of data to be able set the handles. +bool CpuWindows::CreatePerfOsCpuHandles() +{ + // Update the refresher so that there is data available in wbem_enum_. + wbem_refresher_->Refresh(0L); + + // The number of enumerators is the number of processor + 1 (the total). + // This is unknown at this point. + DWORD number_returned = 0; + HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_, + wbem_enum_access_, &number_returned); + // number_returned indicates the number of enumerators that are needed. + if (hr == WBEM_E_BUFFER_TOO_SMALL && + number_returned > number_of_objects_) + { + // Allocate the number IWbemObjectAccess asked for by the + // GetObjects(..) function. + wbem_enum_access_ = new IWbemObjectAccess*[number_returned]; + cpu_usage_ = new WebRtc_UWord32[number_returned]; + previous_processor_timestamp_ = new unsigned __int64[number_returned]; + previous_100ns_timestamp_ = new unsigned __int64[number_returned]; + if ((wbem_enum_access_ == NULL) || (cpu_usage_ == NULL) || + (previous_processor_timestamp_ == NULL) || + (previous_100ns_timestamp_ == NULL)) + { + // Out of memory. + return false; + } + + SecureZeroMemory(wbem_enum_access_, number_returned * + sizeof(IWbemObjectAccess*)); + memset(cpu_usage_, 0, sizeof(int) * number_returned); + memset(previous_processor_timestamp_, 0, sizeof(unsigned __int64) * + number_returned); + memset(previous_100ns_timestamp_, 0, sizeof(unsigned __int64) * + number_returned); + + number_of_objects_ = number_returned; + // Read should be successfull now that memory has been allocated. + hr = wbem_enum_->GetObjects(0L, number_of_objects_, wbem_enum_access_, + &number_returned); + if (FAILED(hr)) + { + return false; + } + } + else + { + // 0 enumerators should not be enough. Something has gone wrong here. + return false; + } + + // Get the enumerator handles that are needed for calculating CPU usage. + CIMTYPE cpu_usage_type; + hr = wbem_enum_access_[0]->GetPropertyHandle(L"PercentProcessorTime", + &cpu_usage_type, + &cpu_usage_handle_); + if (FAILED(hr)) + { + return false; + } + CIMTYPE timestamp_sys_100_ns_type; + hr = wbem_enum_access_[0]->GetPropertyHandle(L"TimeStamp_Sys100NS", + ×tamp_sys_100_ns_type, + ×tamp_sys_100_ns_handle_); + return !FAILED(hr); +} + +bool CpuWindows::Initialize() +{ + if (terminate_) + { + return false; + } + // Initialize COM library. + HRESULT hr = CoInitializeEx(NULL,COINIT_MULTITHREADED); + if (FAILED(hr)) + { + return false; + } + if (FAILED(hr)) + { + return false; + } + + if (!CreateWmiConnection()) + { + return false; + } + if (!CreatePerfOsRefresher()) + { + return false; + } + if (!CreatePerfOsCpuHandles()) + { + return false; + } + has_initialized_ = true; + return true; +} + +bool CpuWindows::Terminate() +{ + if (has_terminated_) + { + return false; + } + // Reverse order of Initialize(). + // Some compilers complain about deleting NULL though it's well defined + if (previous_100ns_timestamp_ != NULL) + { + delete[] previous_100ns_timestamp_; + previous_100ns_timestamp_ = NULL; + } + if (previous_processor_timestamp_ != NULL) + { + delete[] previous_processor_timestamp_; + previous_processor_timestamp_ = NULL; + } + if (cpu_usage_ != NULL) + { + delete[] cpu_usage_; + cpu_usage_ = NULL; + } + if (wbem_enum_access_ != NULL) + { + for (DWORD i = 0; i < number_of_objects_; i++) + { + if(wbem_enum_access_[i] != NULL) + { + wbem_enum_access_[i]->Release(); + } + } + delete[] wbem_enum_access_; + wbem_enum_access_ = NULL; + } + if (wbem_enum_ != NULL) + { + wbem_enum_->Release(); + wbem_enum_ = NULL; + } + if (wbem_refresher_ != NULL) + { + wbem_refresher_->Release(); + wbem_refresher_ = NULL; + } + if (wbem_service_proxy_ != NULL) + { + wbem_service_proxy_->Release(); + wbem_service_proxy_ = NULL; + } + if (wbem_service_ != NULL) + { + wbem_service_->Release(); + wbem_service_ = NULL; + } + // CoUninitialized should be called once for every CoInitializeEx. + // Regardless if it failed or not. + CoUninitialize(); + has_terminated_ = true; + return true; +} + +bool CpuWindows::UpdateCpuUsage() +{ + wbem_refresher_->Refresh(0L); + DWORD number_returned = 0; + HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_, + wbem_enum_access_,&number_returned); + if (FAILED(hr)) + { + // wbem_enum_access_ has already been allocated. Unless the number of + // CPUs change runtime this should not happen. + return false; + } + unsigned __int64 cpu_usage = 0; + unsigned __int64 timestamp_100ns = 0; + bool returnValue = true; + for (DWORD i = 0; i < number_returned; i++) + { + hr = wbem_enum_access_[i]->ReadQWORD(cpu_usage_handle_,&cpu_usage); + if (FAILED(hr)) + { + returnValue = false; + } + hr = wbem_enum_access_[i]->ReadQWORD(timestamp_sys_100_ns_handle_, + ×tamp_100ns); + if (FAILED(hr)) + { + returnValue = false; + } + wbem_enum_access_[i]->Release(); + wbem_enum_access_[i] = NULL; + + const bool wrapparound = + (previous_processor_timestamp_[i] > cpu_usage) || + (previous_100ns_timestamp_[i] > timestamp_100ns); + const bool first_time = (previous_processor_timestamp_[i] == 0) || + (previous_100ns_timestamp_[i] == 0); + if (wrapparound || first_time) + { + previous_processor_timestamp_[i] = cpu_usage; + previous_100ns_timestamp_[i] = timestamp_100ns; + continue; + } + const unsigned __int64 processor_timestamp_delta = + cpu_usage - previous_processor_timestamp_[i]; + const unsigned __int64 timestamp_100ns_delta = + timestamp_100ns - previous_100ns_timestamp_[i]; + + if (processor_timestamp_delta >= timestamp_100ns_delta) + { + cpu_usage_[i] = 0; + } else { + // Quotient must be float since the division is guaranteed to yield + // a value between 0 and 1 which is 0 in integer division. + const float delta_quotient = + static_cast<float>(processor_timestamp_delta) / + static_cast<float>(timestamp_100ns_delta); + cpu_usage_[i] = 100 - static_cast<WebRtc_UWord32>(delta_quotient * + 100); + } + previous_processor_timestamp_[i] = cpu_usage; + previous_100ns_timestamp_[i] = timestamp_100ns; + } + return returnValue; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/cpu_win.h b/src/system_wrappers/source/cpu_win.h new file mode 100644 index 0000000000..d15073c0ba --- /dev/null +++ b/src/system_wrappers/source/cpu_win.h @@ -0,0 +1,103 @@ +// This file contains a Windows implementation of CpuWrapper. +// Note: Windows XP, Windows Server 2003 are the minimum requirements. +// The requirements are due to the implementation being based on +// WMI. +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ + +#include "cpu_wrapper.h" + +#include <Wbemidl.h> + +namespace webrtc { +class ConditionVariableWrapper; +class CriticalSectionWrapper; +class EventWrapper; +class ThreadWrapper; + +class CpuWindows : public CpuWrapper +{ +public: + virtual WebRtc_Word32 CpuUsage(); + virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* /*pProcessName*/, + WebRtc_UWord32 /*length*/) {return -1;} + virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 /*dwProcessID*/) {return -1;} + + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& num_cores, + WebRtc_UWord32*& cpu_usage); + + virtual void Reset() {} + virtual void Stop() {} + + CpuWindows(); + virtual ~CpuWindows(); +private: + bool AllocateComplexDataTypes(); + void DeAllocateComplexDataTypes(); + + void StartPollingCpu(); + bool StopPollingCpu(); + + static bool Process(void* thread_object); + bool ProcessImpl(); + + bool CreateWmiConnection(); + bool CreatePerfOsRefresher(); + bool CreatePerfOsCpuHandles(); + bool Initialize(); + bool Terminate(); + + bool UpdateCpuUsage(); + + ThreadWrapper* cpu_polling_thread; + + bool initialize_; + bool has_initialized_; + CriticalSectionWrapper* init_crit_; + ConditionVariableWrapper* init_cond_; + + bool terminate_; + bool has_terminated_; + CriticalSectionWrapper* terminate_crit_; + ConditionVariableWrapper* terminate_cond_; + + // For sleep with wake-up functionality. + EventWrapper* sleep_event; + + // Will be an array. Just care about CPU 0 for now. + WebRtc_UWord32* cpu_usage_; + + // One IWbemObjectAccess for each processor and one for the total. + // 0-n-1 is the individual processors. + // n is the total. + IWbemObjectAccess** wbem_enum_access_; + DWORD number_of_objects_; + + // Cpu timestamp + long cpu_usage_handle_; + unsigned __int64* previous_processor_timestamp_; + + // Timestamp + long timestamp_sys_100_ns_handle_; + unsigned __int64* previous_100ns_timestamp_; + + IWbemServices* wbem_service_; + IWbemServices* wbem_service_proxy_; + + IWbemRefresher* wbem_refresher_; + + IWbemHiPerfEnum* wbem_enum_; + +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ diff --git a/src/system_wrappers/source/cpu_wrapper_unittest.cc b/src/system_wrappers/source/cpu_wrapper_unittest.cc index dd49c3ac94..cd149dc30f 100644 --- a/src/system_wrappers/source/cpu_wrapper_unittest.cc +++ b/src/system_wrappers/source/cpu_wrapper_unittest.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -23,7 +23,14 @@ using webrtc::EventWrapper; using webrtc::scoped_ptr; using webrtc::Trace; -TEST(CpuWrapperTest, Usage) { +// This test is flaky on Windows/Release. +// http://code.google.com/p/webrtc/issues/detail?id=290 +#ifdef _WIN32 +#define MAYBE_Usage DISABLED_Usage +#else +#define MAYBE_Usage Usage +#endif +TEST(CpuWrapperTest, MAYBE_Usage) { Trace::CreateTrace(); std::string trace_file = webrtc::test::OutputPath() + "cpu_wrapper_unittest.txt"; @@ -42,7 +49,7 @@ TEST(CpuWrapperTest, Usage) { // Initializing the CPU measurements may take a couple of seconds on Windows. // Since the initialization is lazy we need to wait until it is completed. // Should not take more than 10000 ms. - while (cpu_usage_available && (++num_iterations < 10000)) { + while (!cpu_usage_available && (++num_iterations < 10000)) { if (cores != NULL) { ASSERT_GT(num_cores, 0u); break; diff --git a/src/system_wrappers/source/critical_section_posix.cc b/src/system_wrappers/source/critical_section_posix.cc index b499b9ffe2..70f85f9a68 100644 --- a/src/system_wrappers/source/critical_section_posix.cc +++ b/src/system_wrappers/source/critical_section_posix.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -8,31 +8,39 @@ * 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. There is currently +// no equivalent to DCHECK_EQ in WebRTC code so this is the best we can do here. +// TODO(henrike): add logging when pthread synchronization APIs are failing. + #include "critical_section_posix.h" namespace webrtc { + CriticalSectionPosix::CriticalSectionPosix() { pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&_mutex, &attr); + (void) pthread_mutexattr_init(&attr); + (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + (void) pthread_mutex_init(&_mutex, &attr); } CriticalSectionPosix::~CriticalSectionPosix() { - pthread_mutex_destroy(&_mutex); + (void) pthread_mutex_destroy(&_mutex); } void CriticalSectionPosix::Enter() { - pthread_mutex_lock(&_mutex); + (void) pthread_mutex_lock(&_mutex); } void CriticalSectionPosix::Leave() { - pthread_mutex_unlock(&_mutex); + (void) pthread_mutex_unlock(&_mutex); } + } // namespace webrtc diff --git a/src/system_wrappers/source/critical_section_unittest.cc b/src/system_wrappers/source/critical_section_unittest.cc new file mode 100644 index 0000000000..c48b9f7515 --- /dev/null +++ b/src/system_wrappers/source/critical_section_unittest.cc @@ -0,0 +1,167 @@ +/* + * 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. + */ + +#ifdef _WIN32 +// For Sleep() +#include <windows.h> +#else +// For nanosleep() +#include <time.h> +#endif + +#include "system_wrappers/interface/critical_section_wrapper.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/sleep.h" +#include "system_wrappers/interface/thread_wrapper.h" +#include "system_wrappers/interface/trace.h" +#include "system_wrappers/source/unittest_utilities.h" + +namespace webrtc { + +namespace { + +const bool kLogTrace = false; // Set to true to enable debug logging to stdout. + +#define LOG(...) WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, __VA_ARGS__); + +// 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_; + LOG("Inc to %d", count_); + } + + int Count() const { + CriticalSectionScoped cs(crit_sect_); + return count_; + } + + private: + CriticalSectionWrapper* crit_sect_; + int count_; +}; + +class CritSectTest : public ::testing::Test { + public: + CritSectTest() : trace_(kLogTrace) { + } + + // 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(); + } + LOG("Test looped %d times\n", loop_counter); + return (count->Count() >= target); + } + + private: + ScopedTracing trace_; +}; + +bool LockUnlockThenStopRunFunction(void* obj) { + LOG("Wait starting"); + ProtectedCount* the_count = static_cast<ProtectedCount*> (obj); + LOG("Wait incrementing"); + the_count->Increment(); + LOG("Wait returning"); + return false; +} + +TEST_F(CritSectTest, ThreadWakesOnce) { + CriticalSectionWrapper* crit_sect + = CriticalSectionWrapper::CreateCriticalSection(); + ProtectedCount count(crit_sect); + ThreadWrapper* thread = ThreadWrapper::CreateThread( + &LockUnlockThenStopRunFunction, &count); + unsigned int id = 42; + crit_sect->Enter(); + ASSERT_TRUE(thread->Start(id)); + 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 thread; + delete crit_sect; +} + +bool LockUnlockRunFunction(void* obj) { + LOG("Wait starting"); + ProtectedCount* the_count = static_cast<ProtectedCount*> (obj); + LOG("Wait incrementing"); + the_count->Increment(); + SwitchProcess(); + LOG("Wait returning"); + return true; +} + +TEST_F(CritSectTest, ThreadWakesTwice) { + CriticalSectionWrapper* crit_sect + = CriticalSectionWrapper::CreateCriticalSection(); + ProtectedCount count(crit_sect); + ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction, + &count); + unsigned int id = 42; + crit_sect->Enter(); // Make sure counter stays 0 until we wait for it. + ASSERT_TRUE(thread->Start(id)); + 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(); + + thread->SetNotAlive(); // Tell thread to exit once run function finishes. + SwitchProcess(); + EXPECT_LT(count_before, count.Count()); + EXPECT_TRUE(thread->Stop()); + delete thread; + delete crit_sect; +} + +} // anonymous namespace + +} // namespace webrtc diff --git a/src/system_wrappers/source/critical_section_win.cc b/src/system_wrappers/source/critical_section_win.cc new file mode 100644 index 0000000000..bbc66e5c7d --- /dev/null +++ b/src/system_wrappers/source/critical_section_win.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "critical_section_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/src/system_wrappers/source/critical_section_win.h b/src/system_wrappers/source/critical_section_win.h new file mode 100644 index 0000000000..9556fa9556 --- /dev/null +++ b/src/system_wrappers/source/critical_section_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_CRITICAL_SECTION_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ + +#include "typedefs.h" +#include "critical_section_wrapper.h" +#include <windows.h> + +namespace webrtc { +class CriticalSectionWindows : public CriticalSectionWrapper +{ +public: + CriticalSectionWindows(); + + virtual ~CriticalSectionWindows(); + + virtual void Enter(); + virtual void Leave(); + +private: + CRITICAL_SECTION crit; + + friend class ConditionVariableWindows; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ diff --git a/src/system_wrappers/source/event_win.cc b/src/system_wrappers/source/event_win.cc new file mode 100644 index 0000000000..efcb5af870 --- /dev/null +++ b/src/system_wrappers/source/event_win.cc @@ -0,0 +1,84 @@ +/* + * 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 "event_win.h" + +#include "Mmsystem.h" + +namespace webrtc { +EventWindows::EventWindows() + : _event(::CreateEvent(NULL /* security attributes */, + FALSE /* manual reset */, + FALSE /* initial state */, + NULL /* name of event */)), + _timerID(NULL) +{ +} + +EventWindows::~EventWindows() +{ + CloseHandle(_event); +} + +bool EventWindows::Set() +{ + // Note: setting an event that is already set has no effect. + return SetEvent(_event) == 1 ? true : false; +} + +bool EventWindows::Reset() +{ + return ResetEvent(_event) == 1 ? true : false; +} + +EventTypeWrapper EventWindows::Wait(unsigned long maxTime) +{ + unsigned long res = WaitForSingleObject(_event, maxTime); + switch(res) + { + case WAIT_OBJECT_0: + return kEventSignaled; + case WAIT_TIMEOUT: + return kEventTimeout; + default: + return kEventError; + } +} + +bool EventWindows::StartTimer(bool periodic, unsigned long time) +{ + if (_timerID != NULL) + { + timeKillEvent(_timerID); + _timerID=NULL; + } + if (periodic) + { + _timerID=timeSetEvent(time, 0,(LPTIMECALLBACK)HANDLE(_event),0, + TIME_PERIODIC|TIME_CALLBACK_EVENT_PULSE); + } else { + _timerID=timeSetEvent(time, 0,(LPTIMECALLBACK)HANDLE(_event),0, + TIME_ONESHOT|TIME_CALLBACK_EVENT_SET); + } + + if (_timerID == NULL) + { + return false; + } + return true; +} + +bool EventWindows::StopTimer() +{ + timeKillEvent(_timerID); + _timerID = NULL; + return true; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/event_win.h b/src/system_wrappers/source/event_win.h new file mode 100644 index 0000000000..8ca1360c35 --- /dev/null +++ b/src/system_wrappers/source/event_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_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ + +#include <windows.h> + +#include "event_wrapper.h" + +#include "typedefs.h" + +namespace webrtc { +class EventWindows : public EventWrapper +{ +public: + EventWindows(); + virtual ~EventWindows(); + + virtual EventTypeWrapper Wait(unsigned long maxTime); + virtual bool Set(); + virtual bool Reset(); + + virtual bool StartTimer(bool periodic, unsigned long time); + virtual bool StopTimer(); + +private: + HANDLE _event; + WebRtc_UWord32 _timerID; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ diff --git a/src/system_wrappers/source/file_impl.cc b/src/system_wrappers/source/file_impl.cc index d163bf6c26..4d06c54707 100644 --- a/src/system_wrappers/source/file_impl.cc +++ b/src/system_wrappers/source/file_impl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -118,7 +118,7 @@ int FileWrapperImpl::OpenFile(const char *fileNameUTF8, bool readOnly, bool loop, bool text) { size_t length = strlen(fileNameUTF8); - if (length > kMaxFileNameSize) + if (length > kMaxFileNameSize - 1) { return -1; } diff --git a/src/system_wrappers/source/rw_lock.cc b/src/system_wrappers/source/rw_lock.cc index b308358d8a..16da0e321d 100644 --- a/src/system_wrappers/source/rw_lock.cc +++ b/src/system_wrappers/source/rw_lock.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -14,9 +14,6 @@ #if defined(_WIN32) #include "rw_lock_win.h" -#elif defined(WEBRTC_ANDROID) - #include <stdlib.h> - #include "rw_lock_generic.h" #else #include "rw_lock_posix.h" #endif @@ -26,8 +23,6 @@ RWLockWrapper* RWLockWrapper::CreateRWLock() { #ifdef _WIN32 RWLockWrapper* lock = new RWLockWindows(); -#elif defined(WEBRTC_ANDROID) - RWLockWrapper* lock = new RWLockWrapperGeneric(); #else RWLockWrapper* lock = new RWLockPosix(); #endif diff --git a/src/system_wrappers/source/rw_lock_win.cc b/src/system_wrappers/source/rw_lock_win.cc new file mode 100644 index 0000000000..82cd0ac04f --- /dev/null +++ b/src/system_wrappers/source/rw_lock_win.cc @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rw_lock_win.h" + +#include "critical_section_wrapper.h" +#include "condition_variable_wrapper.h" +#include "trace.h" + +// TODO (hellner) why not just use the rw_lock_generic.cc solution if +// native is not supported? Unnecessary redundancy! + +namespace webrtc { +bool RWLockWindows::_winSupportRWLockPrimitive = false; +static HMODULE library = NULL; + +PInitializeSRWLock _PInitializeSRWLock; +PAcquireSRWLockExclusive _PAcquireSRWLockExclusive; +PAcquireSRWLockShared _PAcquireSRWLockShared; +PReleaseSRWLockShared _PReleaseSRWLockShared; +PReleaseSRWLockExclusive _PReleaseSRWLockExclusive; + +RWLockWindows::RWLockWindows() + : _critSectPtr(NULL), + _readCondPtr(NULL), + _writeCondPtr(NULL), + _readersActive(0), + _writerActive(false), + _readersWaiting(0), + _writersWaiting(0) +{ +} + +RWLockWindows::~RWLockWindows() +{ + delete _writeCondPtr; + delete _readCondPtr; + delete _critSectPtr; +} + +int RWLockWindows::Init() +{ + if(!library) + { + // Use native implementation if supported (i.e Vista+) + library = LoadLibrary(TEXT("Kernel32.dll")); + if(library) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Kernel.dll"); + + _PInitializeSRWLock = + (PInitializeSRWLock)GetProcAddress( + library, + "InitializeSRWLock"); + + _PAcquireSRWLockExclusive = + (PAcquireSRWLockExclusive)GetProcAddress( + library, + "AcquireSRWLockExclusive"); + _PReleaseSRWLockExclusive = + (PReleaseSRWLockExclusive)GetProcAddress( + library, + "ReleaseSRWLockExclusive"); + _PAcquireSRWLockShared = + (PAcquireSRWLockShared)GetProcAddress( + library, + "AcquireSRWLockShared"); + _PReleaseSRWLockShared = + (PReleaseSRWLockShared)GetProcAddress( + library, + "ReleaseSRWLockShared"); + + if( _PInitializeSRWLock && + _PAcquireSRWLockExclusive && + _PReleaseSRWLockExclusive && + _PAcquireSRWLockShared && + _PReleaseSRWLockShared ) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Simple RW Lock"); + _winSupportRWLockPrimitive = true; + } + } + } + if(_winSupportRWLockPrimitive) + { + _PInitializeSRWLock(&_lock); + } else { + _critSectPtr = CriticalSectionWrapper::CreateCriticalSection(); + _readCondPtr = ConditionVariableWrapper::CreateConditionVariable(); + _writeCondPtr = ConditionVariableWrapper::CreateConditionVariable(); + } + return 0; +} + +void RWLockWindows::AcquireLockExclusive() +{ + if (_winSupportRWLockPrimitive) + { + _PAcquireSRWLockExclusive(&_lock); + } else { + _critSectPtr->Enter(); + + if (_writerActive || _readersActive > 0) + { + ++_writersWaiting; + while (_writerActive || _readersActive > 0) + { + _writeCondPtr->SleepCS(*_critSectPtr); + } + --_writersWaiting; + } + _writerActive = true; + _critSectPtr->Leave(); + } +} + +void RWLockWindows::ReleaseLockExclusive() +{ + if(_winSupportRWLockPrimitive) + { + _PReleaseSRWLockExclusive(&_lock); + } else { + _critSectPtr->Enter(); + _writerActive = false; + if (_writersWaiting > 0) + { + _writeCondPtr->Wake(); + + }else if (_readersWaiting > 0) { + _readCondPtr->WakeAll(); + } + _critSectPtr->Leave(); + } +} + +void RWLockWindows::AcquireLockShared() +{ + if(_winSupportRWLockPrimitive) + { + _PAcquireSRWLockShared(&_lock); + } else + { + _critSectPtr->Enter(); + if (_writerActive || _writersWaiting > 0) + { + ++_readersWaiting; + + while (_writerActive || _writersWaiting > 0) + { + _readCondPtr->SleepCS(*_critSectPtr); + } + --_readersWaiting; + } + ++_readersActive; + _critSectPtr->Leave(); + } +} + +void RWLockWindows::ReleaseLockShared() +{ + if(_winSupportRWLockPrimitive) + { + _PReleaseSRWLockShared(&_lock); + } else + { + _critSectPtr->Enter(); + + --_readersActive; + + if (_readersActive == 0 && _writersWaiting > 0) + { + _writeCondPtr->Wake(); + } + _critSectPtr->Leave(); + } +} +} // namespace webrtc diff --git a/src/system_wrappers/source/rw_lock_win.h b/src/system_wrappers/source/rw_lock_win.h new file mode 100644 index 0000000000..dc5355e4d6 --- /dev/null +++ b/src/system_wrappers/source/rw_lock_win.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ + +#include "rw_lock_wrapper.h" + +#include <Windows.h> + +#if !defined(RTL_SRWLOCK_INIT) + typedef struct _RTL_SRWLOCK + { + void* Ptr; + } RTL_SRWLOCK, *PRTL_SRWLOCK; + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +#endif + +namespace webrtc { +class CriticalSectionWrapper; +class ConditionVariableWrapper; + +typedef void (WINAPI *PInitializeSRWLock)(PSRWLOCK); + +typedef void (WINAPI *PAcquireSRWLockExclusive)(PSRWLOCK); +typedef void (WINAPI *PReleaseSRWLockExclusive)(PSRWLOCK); + +typedef void (WINAPI *PAcquireSRWLockShared)(PSRWLOCK); +typedef void (WINAPI *PReleaseSRWLockShared)(PSRWLOCK); + + +class RWLockWindows :public RWLockWrapper +{ +public: + RWLockWindows(); + virtual ~RWLockWindows(); + + virtual void AcquireLockExclusive(); + virtual void ReleaseLockExclusive(); + + virtual void AcquireLockShared(); + virtual void ReleaseLockShared(); + +protected: + virtual int Init(); + +private: + // For native implementation. + static bool _winSupportRWLockPrimitive; + SRWLOCK _lock; + + // Genric implementation, fallback if native is not supported. + CriticalSectionWrapper* _critSectPtr; + ConditionVariableWrapper* _readCondPtr; + ConditionVariableWrapper* _writeCondPtr; + + int _readersActive; + bool _writerActive; + int _readersWaiting; + int _writersWaiting; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ diff --git a/src/system_wrappers/source/set_thread_name_win.h b/src/system_wrappers/source/set_thread_name_win.h new file mode 100644 index 0000000000..a46f4d6305 --- /dev/null +++ b/src/system_wrappers/source/set_thread_name_win.h @@ -0,0 +1,43 @@ +/* + * Use of this source code is governed by the MICROSOFT LIMITED PUBLIC LICENSE + * copyright license which can be found in the LICENSE file in the + * third_party_mods/mslpl directory of the source tree or at + * http://msdn.microsoft.com/en-us/cc300389.aspx#P. + */ +/* + * The original code can be found here: + * http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ + +namespace webrtc { + +struct THREADNAME_INFO +{ + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1 = caller thread) + DWORD dwFlags; // reserved for future use, must be zero +}; + +void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), + (ULONG_PTR*)&info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } +} +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ diff --git a/src/system_wrappers/source/sleep.cc b/src/system_wrappers/source/sleep.cc new file mode 100644 index 0000000000..be8523857c --- /dev/null +++ b/src/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 "system_wrappers/interface/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/src/system_wrappers/source/sort.cc b/src/system_wrappers/source/sort.cc index f44b644978..34aa4373ee 100644 --- a/src/system_wrappers/source/sort.cc +++ b/src/system_wrappers/source/sort.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -412,8 +412,6 @@ namespace webrtc case TYPE_Float64: StdSort<double>(data, numOfElements); break; - default: - return -1; } #endif return 0; @@ -543,9 +541,9 @@ namespace webrtc return StdKeySort<float>(data, key, numOfElements, sizeOfElement); case TYPE_Float64: return StdKeySort<double>(data, key, numOfElements, sizeOfElement); - default: - return -1; } + assert(false); + return -1; #endif } } // namespace webrtc diff --git a/src/system_wrappers/source/system_wrappers.gyp b/src/system_wrappers/source/system_wrappers.gyp index ce2438ffe9..b530d6f483 100644 --- a/src/system_wrappers/source/system_wrappers.gyp +++ b/src/system_wrappers/source/system_wrappers.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +# 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 @@ -23,7 +23,8 @@ }, 'sources': [ '../interface/aligned_malloc.h', - '../interface/atomic32_wrapper.h', + '../interface/atomic32.h', + '../interface/compile_assert.h', '../interface/condition_variable_wrapper.h', '../interface/cpu_info.h', '../interface/cpu_wrapper.h', @@ -41,16 +42,16 @@ '../interface/rw_lock_wrapper.h', '../interface/scoped_ptr.h', '../interface/scoped_refptr.h', + '../interface/sleep.h', '../interface/sort.h', '../interface/static_instance.h', '../interface/thread_wrapper.h', '../interface/tick_util.h', '../interface/trace.h', 'aligned_malloc.cc', - 'atomic32.cc', - 'atomic32_linux.h', - 'atomic32_mac.h', - 'atomic32_win.h', + 'atomic32_mac.cc', + 'atomic32_posix.cc', + 'atomic32_win.cc', 'condition_variable.cc', 'condition_variable_posix.cc', 'condition_variable_posix.h', @@ -88,6 +89,7 @@ 'rw_lock_posix.h', 'rw_lock_win.cc', 'rw_lock_win.h', + 'sleep.cc', 'sort.cc', 'thread.cc', 'thread_posix.cc', @@ -109,6 +111,9 @@ },{ 'sources!': [ 'data_log.cc', ], },], + ['OS=="android"', { + 'dependencies': [ 'cpu_features_android', ], + }], ['OS=="linux"', { 'link_settings': { 'libraries': [ '-lrt', ], @@ -118,6 +123,9 @@ 'link_settings': { 'libraries': [ '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework', ], }, + 'sources!': [ + 'atomic32_posix.cc', + ], }], ['OS=="win"', { 'link_settings': { @@ -147,18 +155,41 @@ }, ], # targets 'conditions': [ - ['build_with_chromium==0', { + ['OS=="android"', { + 'targets': [ + { + 'variables': { + # Treat this as third-party code. + 'chromium_code': 0, + }, + 'target_name': 'cpu_features_android', + 'type': '<(library)', + 'sources': [ + 'android/cpu-features.c', + 'android/cpu-features.h', + # TODO(leozwang): Ideally we want to audomatically exclude .c files + # as with .cc files, gyp currently only excludes .cc files. + 'cpu_features_android.c', + ], + }, + ], + }], + ['include_tests==1', { 'targets': [ { 'target_name': 'system_wrappers_unittests', 'type': 'executable', 'dependencies': [ 'system_wrappers', - '<(webrtc_root)/../testing/gtest.gyp:gtest', - '<(webrtc_root)/../test/test.gyp:test_support_main', + '<(DEPTH)/testing/gtest.gyp:gtest', + '<(webrtc_root)/test/test.gyp:test_support_main', ], 'sources': [ + 'condition_variable_unittest.cc', 'cpu_wrapper_unittest.cc', + 'cpu_measurement_harness.h', + 'cpu_measurement_harness.cc', + 'critical_section_unittest.cc', 'list_unittest.cc', 'map_unittest.cc', 'data_log_unittest.cc', @@ -166,6 +197,9 @@ 'data_log_helpers_unittest.cc', 'data_log_c_helpers_unittest.c', 'data_log_c_helpers_unittest.h', + 'thread_unittest.cc', + 'trace_unittest.cc', + 'unittest_utilities_unittest.cc', ], 'conditions': [ ['enable_data_logging==1', { @@ -176,7 +210,7 @@ ], }, ], # targets - }], # build_with_chromium + }], # include_tests ], # conditions } diff --git a/src/system_wrappers/source/thread_posix.cc b/src/system_wrappers/source/thread_posix.cc index eb0e8f46a0..6334490f78 100644 --- a/src/system_wrappers/source/thread_posix.cc +++ b/src/system_wrappers/source/thread_posix.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -8,6 +8,40 @@ * be found in the AUTHORS file in the root of the source tree. */ +// The state of a thread is controlled by the two member variables +// _alive and _dead. +// _alive represents the state the thread has been ordered to achieve. +// It is set to true by the thread at startup, and is set to false by +// other threads, using SetNotAlive() and Stop(). +// _dead represents the state the thread has achieved. +// It is written by the thread encapsulated by this class only +// (except at init). It is read only by the Stop() method. +// The Run() method fires _event when it's started; this ensures that the +// Start() method does not continue until after _dead is false. +// This protects against premature Stop() calls from the creator thread, but +// not from other threads. + +// Their transitions and states: +// _alive _dead Set by +// false true Constructor +// true false Run() method entry +// false any Run() method runFunction failure +// any false Run() method exit (happens only with _alive false) +// false any SetNotAlive +// false any Stop Stop waits for _dead to become true. +// +// Summarized a different way: +// Variable Writer Reader +// _alive Constructor(false) Run.loop +// Run.start(true) +// Run.fail(false) +// SetNotAlive(false) +// Stop(false) +// +// _dead Constructor(true) Stop.loop +// Run.start(false) +// Run.exit(true) + #include "thread_posix.h" #include <errno.h> @@ -22,8 +56,13 @@ #include <sys/prctl.h> #endif -#include "event_wrapper.h" -#include "trace.h" +#if defined(WEBRTC_MAC) +#include <mach/mach.h> +#endif + +#include "system_wrappers/interface/critical_section_wrapper.h" +#include "system_wrappers/interface/event_wrapper.h" +#include "system_wrappers/interface/trace.h" namespace webrtc { extern "C" @@ -35,17 +74,6 @@ extern "C" } } -#if (defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)) -static pid_t gettid() -{ -#if defined(__NR_gettid) - return syscall(__NR_gettid); -#else - return -1; -#endif -} -#endif - ThreadWrapper* ThreadPosix::Create(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, const char* threadName) { @@ -67,22 +95,37 @@ ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, const char* threadName) : _runFunction(func), _obj(obj), + _crit_state(CriticalSectionWrapper::CreateCriticalSection()), _alive(false), _dead(true), _prio(prio), _event(EventWrapper::Create()), - _setThreadName(false) -{ -#ifdef WEBRTC_LINUX - _linuxPid = -1; + _name(), + _setThreadName(false), +#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) + _pid(-1), #endif + _attr(), + _thread(0) +{ if (threadName != NULL) { _setThreadName = true; strncpy(_name, threadName, kThreadMaxNameLength); + _name[kThreadMaxNameLength - 1] = '\0'; } } +uint32_t ThreadWrapper::GetThreadId() { +#if defined(WEBRTC_ANDROID) || defined(WEBRTC_LINUX) + return static_cast<uint32_t>(syscall(__NR_gettid)); +#elif defined(WEBRTC_MAC) + return static_cast<uint32_t>(mach_thread_self()); +#else + return reinterpret_cast<uint32_t>(pthread_self()); +#endif +} + int ThreadPosix::Construct() { int result = 0; @@ -104,7 +147,6 @@ int ThreadPosix::Construct() { return -1; } - return 0; } @@ -112,6 +154,7 @@ ThreadPosix::~ThreadPosix() { pthread_attr_destroy(&_attr); delete _event; + delete _crit_state; } #define HAS_THREAD_ID !defined(MAC_IPHONE) && !defined(MAC_IPHONE_SIM) && \ @@ -180,8 +223,6 @@ bool ThreadPosix::Start(unsigned int& /*threadID*/) case kRealtimePriority: param.sched_priority = maxPrio - 1; break; - default: - return false; } result = pthread_setschedparam(_thread, policy, ¶m); if (result == EINVAL) @@ -191,33 +232,40 @@ bool ThreadPosix::Start(unsigned int& /*threadID*/) return true; } -#if (defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)) +// CPU_ZERO and CPU_SET are not available in NDK r7, so disable +// SetAffinity on Android for now. +#if (defined(WEBRTC_LINUX) && (!defined(WEBRTC_ANDROID))) bool ThreadPosix::SetAffinity(const int* processorNumbers, - const unsigned int amountOfProcessors) -{ - if (!processorNumbers || (amountOfProcessors == 0)) - { - return false; - } - - cpu_set_t mask; - CPU_ZERO(&mask); - - for(unsigned int processor = 0; - processor < amountOfProcessors; - processor++) - { - CPU_SET(processorNumbers[processor], &mask); - } - const int result = sched_setaffinity(_linuxPid, (unsigned int)sizeof(mask), - &mask); - if (result != 0) - { - return false; + const unsigned int amountOfProcessors) { + if (!processorNumbers || (amountOfProcessors == 0)) { + return false; + } + cpu_set_t mask; + CPU_ZERO(&mask); - } - return true; + for (unsigned int processor = 0; + processor < amountOfProcessors; + processor++) { + CPU_SET(processorNumbers[processor], &mask); + } +#if defined(WEBRTC_ANDROID) + // Android. + const int result = syscall(__NR_sched_setaffinity, + _pid, + sizeof(mask), + &mask); +#else + // "Normal" Linux. + const int result = sched_setaffinity(_pid, + sizeof(mask), + &mask); +#endif + if (result != 0) { + return false; + } + return true; } + #else // NOTE: On Mac OS X, use the Thread affinity API in // /usr/include/mach/thread_policy.h: thread_policy_set and mach_thread_self() @@ -230,6 +278,7 @@ bool ThreadPosix::SetAffinity(const int* , const unsigned int) void ThreadPosix::SetNotAlive() { + CriticalSectionScoped cs(_crit_state); _alive = false; } @@ -249,18 +298,27 @@ bool ThreadPosix::Shutdown() bool ThreadPosix::Stop() { - _alive = false; + bool dead = false; + { + CriticalSectionScoped cs(_crit_state); + _alive = false; + dead = _dead; + } // TODO (hellner) why not use an event here? // Wait up to 10 seconds for the thread to terminate - for (int i = 0; i < 1000 && !_dead; i++) + for (int i = 0; i < 1000 && !dead; i++) { timespec t; t.tv_sec = 0; t.tv_nsec = 10*1000*1000; nanosleep(&t, NULL); + { + CriticalSectionScoped cs(_crit_state); + dead = _dead; + } } - if (_dead) + if (dead) { return true; } @@ -272,13 +330,13 @@ bool ThreadPosix::Stop() void ThreadPosix::Run() { - _alive = true; - _dead = false; -#ifdef WEBRTC_LINUX - if(_linuxPid == -1) { - _linuxPid = gettid(); + CriticalSectionScoped cs(_crit_state); + _alive = true; + _dead = false; } +#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) + _pid = GetThreadId(); #endif // The event the Start() is waiting for. _event->Set(); @@ -286,38 +344,38 @@ void ThreadPosix::Run() if (_setThreadName) { #ifdef WEBRTC_LINUX - WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, - "Thread with id:%d name:%s started ", _linuxPid, _name); prctl(PR_SET_NAME, (unsigned long)_name, 0, 0, 0); -#else +#endif WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, "Thread with name:%s started ", _name); -#endif - }else + } else { -#ifdef WEBRTC_LINUX - WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, - "Thread with id:%d without name started", _linuxPid); -#else WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Thread without name started"); -#endif } + bool alive = true; do { if (_runFunction) { if (!_runFunction(_obj)) { - _alive = false; + alive = false; } } else { - _alive = false; + alive = false; + } + { + CriticalSectionScoped cs(_crit_state); + if (!alive) { + _alive = false; + } + alive = _alive; } } - while (_alive); + while (alive); if (_setThreadName) { @@ -335,6 +393,9 @@ void ThreadPosix::Run() WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, "Thread without name stopped"); } - _dead = true; + { + CriticalSectionScoped cs(_crit_state); + _dead = true; + } } } // namespace webrtc diff --git a/src/system_wrappers/source/thread_posix.h b/src/system_wrappers/source/thread_posix.h index f664a52e70..45489a8622 100644 --- a/src/system_wrappers/source/thread_posix.h +++ b/src/system_wrappers/source/thread_posix.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -15,6 +15,8 @@ #include <pthread.h> namespace webrtc { + +class CriticalSectionWrapper; class EventWrapper; class ThreadPosix : public ThreadWrapper @@ -47,6 +49,7 @@ private: ThreadObj _obj; // internal state + CriticalSectionWrapper* _crit_state; // Protects _alive and _dead bool _alive; bool _dead; ThreadPriority _prio; @@ -57,12 +60,11 @@ private: bool _setThreadName; // handle to thread +#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) + pid_t _pid; +#endif pthread_attr_t _attr; pthread_t _thread; -#ifdef WEBRTC_LINUX - pid_t _linuxPid; -#endif - }; } // namespace webrtc diff --git a/src/system_wrappers/source/thread_unittest.cc b/src/system_wrappers/source/thread_unittest.cc new file mode 100644 index 0000000000..361424a7fb --- /dev/null +++ b/src/system_wrappers/source/thread_unittest.cc @@ -0,0 +1,96 @@ +/* + * 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 "system_wrappers/interface/thread_wrapper.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/trace.h" + +namespace webrtc { + +const int kLogTrace = 0; + +class TestTraceCallback : public TraceCallback { + public: + virtual void Print(const TraceLevel level, + const char* traceString, + const int length) { + if (traceString) { + char* cmd_print = new char[length+1]; + memcpy(cmd_print, traceString, length); + cmd_print[length] = '\0'; + printf("%s\n", cmd_print); + fflush(stdout); + delete[] cmd_print; + } + } +}; + +class ThreadTest : public ::testing::Test { + public: + ThreadTest() { + StartTrace(); + } + ~ThreadTest() { + StopTrace(); + } + + private: + void StartTrace() { + if (kLogTrace) { + Trace::CreateTrace(); + Trace::SetLevelFilter(webrtc::kTraceAll); + Trace::SetTraceCallback(&trace_); + } + } + + void StopTrace() { + if (kLogTrace) { + Trace::ReturnTrace(); + } + } + + TestTraceCallback trace_; +}; + +// Function that does nothing, and reports success. +bool NullRunFunction(void* /* obj */) { + return true; +} + +TEST_F(ThreadTest, StartStop) { + ThreadWrapper* thread = ThreadWrapper::CreateThread(&NullRunFunction); + unsigned int id = 42; + ASSERT_TRUE(thread->Start(id)); + EXPECT_TRUE(thread->Stop()); + delete thread; +} + +// Function that sets a boolean. +bool SetFlagRunFunction(void* obj) { + bool* obj_as_bool = static_cast<bool*> (obj); + *obj_as_bool = true; + return true; +} + +TEST_F(ThreadTest, RunFunctionIsCalled) { + bool flag = false; + ThreadWrapper* thread = ThreadWrapper::CreateThread(&SetFlagRunFunction, + &flag); + unsigned int id = 42; + ASSERT_TRUE(thread->Start(id)); + // 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); + delete thread; +} + +} // namespace webrtc diff --git a/src/system_wrappers/source/thread_win.cc b/src/system_wrappers/source/thread_win.cc new file mode 100644 index 0000000000..07c586a87c --- /dev/null +++ b/src/system_wrappers/source/thread_win.cc @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "thread_win.h" + +#include <assert.h> +#include <process.h> +#include <stdio.h> +#include <windows.h> + +#include "set_thread_name_win.h" +#include "trace.h" + +namespace webrtc { +ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj, + ThreadPriority prio, const char* threadName) + : ThreadWrapper(), + _runFunction(func), + _obj(obj), + _alive(false), + _dead(true), + _doNotCloseHandle(false), + _prio(prio), + _event(NULL), + _thread(NULL), + _id(0), + _name(), + _setThreadName(false) +{ + _event = EventWrapper::Create(); + _critsectStop = CriticalSectionWrapper::CreateCriticalSection(); + if (threadName != NULL) + { + // Set the thread name to appear in the VS debugger. + _setThreadName = true; + strncpy(_name, threadName, kThreadMaxNameLength); + } +} + +ThreadWindows::~ThreadWindows() +{ +#ifdef _DEBUG + assert(!_alive); +#endif + if (_thread) + { + CloseHandle(_thread); + } + if(_event) + { + delete _event; + } + if(_critsectStop) + { + delete _critsectStop; + } +} + +uint32_t ThreadWrapper::GetThreadId() { + return GetCurrentThreadId(); +} + +unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter) +{ + static_cast<ThreadWindows*>(lpParameter)->Run(); + return 0; +} + +bool ThreadWindows::Start(unsigned int& threadID) +{ + _doNotCloseHandle = false; + + // Set stack size to 1M + _thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0, + &threadID); + if(_thread == NULL) + { + return false; + } + _id = threadID; + _event->Wait(INFINITE); + + switch(_prio) + { + case kLowPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL); + break; + case kNormalPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL); + break; + case kHighPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL); + break; + case kHighestPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST); + break; + case kRealtimePriority: + SetThreadPriority(_thread, THREAD_PRIORITY_TIME_CRITICAL); + break; + }; + return true; +} + +bool ThreadWindows::SetAffinity(const int* processorNumbers, + const unsigned int amountOfProcessors) +{ + DWORD_PTR processorBitMask = 0; + for(unsigned int processorIndex = 0; + processorIndex < amountOfProcessors; + processorIndex++) + { + // Convert from an array with processor numbers to a bitmask + // Processor numbers start at zero. + // TODO (hellner): this looks like a bug. Shouldn't the '=' be a '+='? + // Or even better |= + processorBitMask = 1 << processorNumbers[processorIndex]; + } + return SetThreadAffinityMask(_thread,processorBitMask) != 0; +} + +void ThreadWindows::SetNotAlive() +{ + _alive = false; +} + +bool ThreadWindows::Shutdown() +{ + DWORD exitCode = 0; + BOOL ret = TRUE; + if (_thread) + { + ret = TerminateThread(_thread, exitCode); + _alive = false; + _dead = true; + _thread = NULL; + } + return ret == TRUE; +} + +bool ThreadWindows::Stop() +{ + _critsectStop->Enter(); + // Prevents the handle from being closed in ThreadWindows::Run() + _doNotCloseHandle = true; + _alive = false; + bool signaled = false; + if (_thread && !_dead) + { + _critsectStop->Leave(); + // Wait up to 2 seconds for the thread to complete. + if( WAIT_OBJECT_0 == WaitForSingleObject(_thread, 2000)) + { + signaled = true; + } + _critsectStop->Enter(); + } + if (_thread) + { + CloseHandle(_thread); + _thread = NULL; + } + _critsectStop->Leave(); + + if (_dead || signaled) + { + return true; + } + else + { + return false; + } +} + +void ThreadWindows::Run() +{ + _alive = true; + _dead = false; + _event->Set(); + + // All tracing must be after _event->Set to avoid deadlock in Trace. + if (_setThreadName) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread with name:%s started ", _name); + SetThreadName(-1, _name); // -1, set thread name for the calling thread. + }else + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread without name started"); + } + + do + { + if (_runFunction) + { + if (!_runFunction(_obj)) + { + _alive = false; + } + } else { + _alive = false; + } + } while(_alive); + + if (_setThreadName) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread with name:%s stopped", _name); + } else { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id, + "Thread without name stopped"); + } + + _critsectStop->Enter(); + + if (_thread && !_doNotCloseHandle) + { + HANDLE thread = _thread; + _thread = NULL; + CloseHandle(thread); + } + _dead = true; + + _critsectStop->Leave(); +}; +} // namespace webrtc diff --git a/src/system_wrappers/source/thread_win.h b/src/system_wrappers/source/thread_win.h new file mode 100644 index 0000000000..4fd7523ec9 --- /dev/null +++ b/src/system_wrappers/source/thread_win.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ + +#include "thread_wrapper.h" +#include "event_wrapper.h" +#include "critical_section_wrapper.h" + +#include <windows.h> + +namespace webrtc { + +class ThreadWindows : public ThreadWrapper +{ +public: + ThreadWindows(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, + const char* threadName); + virtual ~ThreadWindows(); + + virtual bool Start(unsigned int& id); + bool SetAffinity(const int* processorNumbers, + const unsigned int amountOfProcessors); + virtual bool Stop(); + virtual void SetNotAlive(); + + static unsigned int WINAPI StartThread(LPVOID lpParameter); + + virtual bool Shutdown(); + +protected: + virtual void Run(); + +private: + ThreadRunFunction _runFunction; + ThreadObj _obj; + + bool _alive; + bool _dead; + + // TODO (hellner) + // _doNotCloseHandle member seem pretty redundant. Should be able to remove + // it. Basically it should be fine to reclaim the handle when calling stop + // and in the destructor. + bool _doNotCloseHandle; + ThreadPriority _prio; + EventWrapper* _event; + CriticalSectionWrapper* _critsectStop; + + HANDLE _thread; + unsigned int _id; + char _name[kThreadMaxNameLength]; + bool _setThreadName; + +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ diff --git a/src/system_wrappers/source/trace_impl.cc b/src/system_wrappers/source/trace_impl.cc index 1156519eb9..c6d9296651 100644 --- a/src/system_wrappers/source/trace_impl.cc +++ b/src/system_wrappers/source/trace_impl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -17,17 +17,16 @@ #include "trace_win.h" #else #include <stdio.h> -#include <time.h> #include <stdarg.h> #include "trace_posix.h" #endif // _WIN32 +#include "system_wrappers/interface/sleep.h" + #define KEY_LEN_CHARS 31 #ifdef _WIN32 - #pragma warning(disable:4355) -// VS 2005: Disable warnings for default initialized arrays. - #pragma warning(disable:4351) +#pragma warning(disable:4355) #endif // _WIN32 namespace webrtc { @@ -94,7 +93,7 @@ TraceImpl::TraceImpl() for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++) { _messageQueue[m][n] = new - WebRtc_Word8[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; + char[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; } } } @@ -108,14 +107,7 @@ bool TraceImpl::StopThread() // TODO (hellner): why not use condition variables to do this? Or let the // worker thread die and let this thread flush remaining // messages? -#ifdef _WIN32 - Sleep(10); -#else - timespec t; - t.tv_sec = 0; - t.tv_nsec = 10*1000000; - nanosleep(&t,NULL); -#endif + SleepMs(10); _thread.SetNotAlive(); // Make sure the thread finishes as quickly as possible (instead of having @@ -147,6 +139,12 @@ TraceImpl::~TraceImpl() } } +WebRtc_Word32 TraceImpl::AddThreadId(char* traceMessage) const { + WebRtc_UWord32 threadId = ThreadWrapper::GetThreadId(); + // Messages is 12 characters. + return sprintf(traceMessage, "%10u; ", threadId); +} + WebRtc_Word32 TraceImpl::AddLevel(char* szMessage, const TraceLevel level) const { switch (level) @@ -277,9 +275,6 @@ WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage, sprintf(traceMessage, " VIDEO PROC:%5ld %5ld;", idEngine, idChannel); break; - default: - assert(false); - return 0; } } else { switch (module) @@ -335,16 +330,13 @@ WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage, case kTraceVideoPreocessing: sprintf (traceMessage, " VIDEO PROC:%11ld;", idl); break; - default: - assert(false); - return 0; } } // All messages are 25 characters. return 25; } -WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8, +WebRtc_Word32 TraceImpl::SetTraceFileImpl(const char* fileNameUTF8, const bool addFileCounter) { CriticalSectionScoped lock(_critsectInterface); @@ -358,7 +350,7 @@ WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8, { _fileCountText = 1; - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize]; + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize]; CreateFileName(fileNameUTF8, fileNameWithCounterUTF8, _fileCountText); if(_traceFile.OpenFile(fileNameWithCounterUTF8, false, false, @@ -379,7 +371,7 @@ WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8, } WebRtc_Word32 TraceImpl::TraceFileImpl( - WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize]) + char fileNameUTF8[FileWrapper::kMaxFileNameSize]) { CriticalSectionScoped lock(_critsectInterface); return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize); @@ -429,8 +421,14 @@ WebRtc_Word32 TraceImpl::AddMessage( void TraceImpl::AddMessageToList( const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE], const WebRtc_UWord16 length, - const TraceLevel level) -{ + const TraceLevel level) { +#ifdef WEBRTC_DIRECT_TRACE + if (_callback) { + _callback->Print(level, traceMessage, length); + } + return; +#endif + CriticalSectionScoped lock(_critsectArray); if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE) @@ -550,8 +548,8 @@ void TraceImpl::WriteToFile() _traceFile.Rewind(); } else { - WebRtc_Word8 oldFileName[FileWrapper::kMaxFileNameSize]; - WebRtc_Word8 newFileName[FileWrapper::kMaxFileNameSize]; + char oldFileName[FileWrapper::kMaxFileNameSize]; + char newFileName[FileWrapper::kMaxFileNameSize]; // get current name _traceFile.FileName(oldFileName, @@ -571,7 +569,7 @@ void TraceImpl::WriteToFile() } if(_rowCountText == 0) { - WebRtc_Word8 message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1]; + char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1]; WebRtc_Word32 length = AddDateTimeInfo(message); if(length != -1) { @@ -637,7 +635,7 @@ void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module, ackLen += len; len = AddThreadId(meassagePtr); - if(len == -1) + if(len < 0) { return; } @@ -663,8 +661,8 @@ bool TraceImpl::TraceCheck(const TraceLevel level) const } bool TraceImpl::UpdateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const { WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); @@ -706,8 +704,8 @@ bool TraceImpl::UpdateFileName( } bool TraceImpl::CreateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const { WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); @@ -760,7 +758,7 @@ WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter) return 0; } -WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize]) +WebRtc_Word32 Trace::TraceFile(char fileName[FileWrapper::kMaxFileNameSize]) { TraceImpl* trace = TraceImpl::GetTrace(); if(trace) @@ -772,7 +770,7 @@ WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSi return -1; } -WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* fileName, +WebRtc_Word32 Trace::SetTraceFile(const char* fileName, const bool addFileCounter) { TraceImpl* trace = TraceImpl::GetTrace(); diff --git a/src/system_wrappers/source/trace_impl.h b/src/system_wrappers/source/trace_impl.h index 455a3d5523..2b85813a88 100644 --- a/src/system_wrappers/source/trace_impl.h +++ b/src/system_wrappers/source/trace_impl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -49,10 +49,10 @@ public: static TraceImpl* CreateInstance(); static TraceImpl* GetTrace(const TraceLevel level = kTraceAll); - WebRtc_Word32 SetTraceFileImpl(const WebRtc_Word8* fileName, + WebRtc_Word32 SetTraceFileImpl(const char* fileName, const bool addFileCounter); WebRtc_Word32 TraceFileImpl( - WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize]); + char fileName[FileWrapper::kMaxFileNameSize]); WebRtc_Word32 SetTraceCallbackImpl(TraceCallback* callback); @@ -69,8 +69,9 @@ protected: static TraceImpl* StaticInstance(CountOperation count_operation, const TraceLevel level = kTraceAll); + WebRtc_Word32 AddThreadId(char* traceMessage) const; + // OS specific implementations - virtual WebRtc_Word32 AddThreadId(char* traceMessage) const = 0; virtual WebRtc_Word32 AddTime(char* traceMessage, const TraceLevel level) const = 0; @@ -98,13 +99,13 @@ private: const TraceLevel level); bool UpdateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const; bool CreateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const; void WriteToFile(); @@ -123,7 +124,7 @@ private: WebRtc_UWord16 _nextFreeIdx[WEBRTC_TRACE_NUM_ARRAY]; TraceLevel _level[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; WebRtc_UWord16 _length[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; - WebRtc_Word8* _messageQueue[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + char* _messageQueue[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; WebRtc_UWord8 _activeQueue; }; } // namespace webrtc diff --git a/src/system_wrappers/source/trace_impl_no_op.cc b/src/system_wrappers/source/trace_impl_no_op.cc index 17528711bc..e74d901a54 100644 --- a/src/system_wrappers/source/trace_impl_no_op.cc +++ b/src/system_wrappers/source/trace_impl_no_op.cc @@ -31,12 +31,12 @@ WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& /*filter*/) } WebRtc_Word32 Trace::TraceFile( - WebRtc_Word8 /*fileName*/[1024]) + char/*fileName*/[1024]) { return -1; } -WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* /*fileName*/, +WebRtc_Word32 Trace::SetTraceFile(const char* /*fileName*/, const bool /*addFileCounter*/) { return -1; diff --git a/src/system_wrappers/source/trace_posix.cc b/src/system_wrappers/source/trace_posix.cc index 198c4349b0..1b8dd934d2 100644 --- a/src/system_wrappers/source/trace_posix.cc +++ b/src/system_wrappers/source/trace_posix.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -14,10 +14,8 @@ #include <stdarg.h> #include <stdio.h> #include <string.h> +#include <sys/time.h> #include <time.h> -#ifdef __linux__ - #include <sys/syscall.h> -#endif #ifdef WEBRTC_ANDROID #include <pthread.h> #else @@ -41,8 +39,9 @@ namespace webrtc { TracePosix::TracePosix() { - _prevAPITickCount = time(NULL); - _prevTickCount = _prevAPITickCount; + struct timeval systemTimeHighRes; + gettimeofday(&systemTimeHighRes, 0); + _prevAPITickCount = _prevTickCount = systemTimeHighRes.tv_sec; } TracePosix::~TracePosix() @@ -50,69 +49,47 @@ TracePosix::~TracePosix() StopThread(); } -WebRtc_Word32 TracePosix::AddThreadId(char* traceMessage) const { -#ifdef __linux__ - pid_t threadId = (pid_t) syscall(__NR_gettid); - sprintf(traceMessage, "%10d; ", threadId); -#else - WebRtc_UWord64 threadId = (WebRtc_UWord64)pthread_self(); - sprintf(traceMessage, "%10llu; ", - static_cast<long long unsigned int>(threadId)); -#endif - // 12 bytes are written. - return 12; -} - WebRtc_Word32 TracePosix::AddTime(char* traceMessage, const TraceLevel level) const { - time_t dwCurrentTimeInSeconds = time(NULL); - struct tm systemTime; - gmtime_r(&dwCurrentTimeInSeconds, &systemTime); - - if(level == kTraceApiCall) + struct timeval systemTimeHighRes; + if (gettimeofday(&systemTimeHighRes, 0) == -1) { - WebRtc_UWord32 dwDeltaTime = dwCurrentTimeInSeconds - _prevTickCount; - _prevTickCount = dwCurrentTimeInSeconds; - - if(_prevTickCount == 0) - { - dwDeltaTime = 0; - } - if(dwDeltaTime > 0x0fffffff) - { - // Either wraparound or data race. - dwDeltaTime = 0; - } - if(dwDeltaTime > 99999) - { - dwDeltaTime = 99999; - } + return -1; + } + struct tm buffer; + const struct tm* systemTime = + localtime_r(&systemTimeHighRes.tv_sec, &buffer); - sprintf(traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.tm_hour, - systemTime.tm_min, systemTime.tm_sec, 0, - static_cast<unsigned long>(dwDeltaTime)); + const WebRtc_UWord32 ms_time = systemTimeHighRes.tv_usec / 1000; + WebRtc_UWord32 prevTickCount = 0; + if (level == kTraceApiCall) + { + prevTickCount = _prevTickCount; + _prevTickCount = ms_time; } else { - WebRtc_UWord32 dwDeltaTime = dwCurrentTimeInSeconds - _prevAPITickCount; - _prevAPITickCount = dwCurrentTimeInSeconds; - if(_prevAPITickCount == 0) - { - dwDeltaTime = 0; - } - if(dwDeltaTime > 0x0fffffff) - { - // Either wraparound or data race. - dwDeltaTime = 0; - } - if(dwDeltaTime > 99999) - { - dwDeltaTime = 99999; - } - sprintf(traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.tm_hour, - systemTime.tm_min, systemTime.tm_sec, 0, - static_cast<unsigned long>(dwDeltaTime)); + prevTickCount = _prevAPITickCount; + _prevAPITickCount = ms_time; + } + WebRtc_UWord32 dwDeltaTime = ms_time - prevTickCount; + if (prevTickCount == 0) + { + dwDeltaTime = 0; + } + if (dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; } - // Messages is 22 characters. + + sprintf(traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime->tm_hour, + systemTime->tm_min, systemTime->tm_sec, ms_time, + static_cast<unsigned long>(dwDeltaTime)); + // Messages are 22 characters. return 22; } @@ -127,7 +104,8 @@ WebRtc_Word32 TracePosix::AddDateTimeInfo(char* traceMessage) const { time_t t; time(&t); - sprintf(traceMessage, "Local Date: %s", ctime(&t)); + char buffer[26]; // man ctime says buffer should have room for >=26 bytes. + sprintf(traceMessage, "Local Date: %s", ctime_r(&t, buffer)); WebRtc_Word32 len = static_cast<WebRtc_Word32>(strlen(traceMessage)); if ('\n' == traceMessage[len - 1]) diff --git a/src/system_wrappers/source/trace_posix.h b/src/system_wrappers/source/trace_posix.h index 099bcc874e..8c37cd2b4e 100644 --- a/src/system_wrappers/source/trace_posix.h +++ b/src/system_wrappers/source/trace_posix.h @@ -21,7 +21,6 @@ public: TracePosix(); virtual ~TracePosix(); - virtual WebRtc_Word32 AddThreadId(char *traceMessage) const; virtual WebRtc_Word32 AddTime(char* traceMessage, const TraceLevel level) const; diff --git a/src/system_wrappers/source/trace_unittest.cc b/src/system_wrappers/source/trace_unittest.cc new file mode 100644 index 0000000000..982e715726 --- /dev/null +++ b/src/system_wrappers/source/trace_unittest.cc @@ -0,0 +1,57 @@ +/* + * 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 "system_wrappers/interface/trace.h" + +#include "gtest/gtest.h" +#include "system_wrappers/source/cpu_measurement_harness.h" +#include "testsupport/fileutils.h" + +using webrtc::CpuMeasurementHarness; +using webrtc::Trace; +using webrtc::kTraceWarning; +using webrtc::kTraceUtility; + +class Logger : public webrtc::CpuTarget { + public: + Logger() { + Trace::CreateTrace(); + std::string trace_file = webrtc::test::OutputPath() + + "trace_unittest.txt"; + Trace::SetTraceFile(trace_file.c_str()); + Trace::SetLevelFilter(webrtc::kTraceAll); + } + virtual ~Logger() { + Trace::ReturnTrace(); + } + + virtual bool DoWork() { + // Use input paremeters to WEBRTC_TRACE that are not likely to be removed + // in future code. E.g. warnings will likely be kept and this file is in + // utility so it should use kTraceUtility. + WEBRTC_TRACE(kTraceWarning, kTraceUtility, 0, "Log line"); + return true; + } +}; + +// This test is disabled because it measures CPU usage. This is flaky because +// the CPU usage for a machine may spike due to OS or other application. +TEST(TraceTest, DISABLED_CpuUsage) { + Logger logger; + const int periodicity_ms = 1; + const int iterations_per_period = 10; + const int duration_ms = 1000; + CpuMeasurementHarness* cpu_harness = + CpuMeasurementHarness::Create(&logger, periodicity_ms, + iterations_per_period, duration_ms); + cpu_harness->Run(); + const int average_cpu = cpu_harness->AverageCpu(); + EXPECT_GE(5, average_cpu); +} diff --git a/src/system_wrappers/source/trace_win.cc b/src/system_wrappers/source/trace_win.cc new file mode 100644 index 0000000000..f81ed8b044 --- /dev/null +++ b/src/system_wrappers/source/trace_win.cc @@ -0,0 +1,131 @@ +/* + * 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 "trace_win.h" + +#include <cassert> +#include <stdarg.h> + +#include "Mmsystem.h" + +#if defined(_DEBUG) + #define BUILDMODE "d" +#elif defined(DEBUG) + #define BUILDMODE "d" +#elif defined(NDEBUG) + #define BUILDMODE "r" +#else + #define BUILDMODE "?" +#endif +#define BUILDTIME __TIME__ +#define BUILDDATE __DATE__ +// Example: "Oct 10 2002 12:05:30 r" +#define BUILDINFO BUILDDATE " " BUILDTIME " " BUILDMODE + +namespace webrtc { +TraceWindows::TraceWindows() + : _prevAPITickCount(0), + _prevTickCount(0) +{ +} + +TraceWindows::~TraceWindows() +{ + StopThread(); +} + +WebRtc_Word32 TraceWindows::AddTime(char* traceMessage, + const TraceLevel level) const +{ + WebRtc_UWord32 dwCurrentTime = timeGetTime(); + SYSTEMTIME systemTime; + GetSystemTime(&systemTime); + + if(level == kTraceApiCall) + { + WebRtc_UWord32 dwDeltaTime = dwCurrentTime- _prevTickCount; + _prevTickCount = dwCurrentTime; + + if(_prevTickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.wHour, + systemTime.wMinute, systemTime.wSecond, + systemTime.wMilliseconds, dwDeltaTime); + } else { + WebRtc_UWord32 dwDeltaTime = dwCurrentTime - _prevAPITickCount; + _prevAPITickCount = dwCurrentTime; + + if(_prevAPITickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.wHour, + systemTime.wMinute, systemTime.wSecond, + systemTime.wMilliseconds, dwDeltaTime); + } + // Messages is 12 characters. + return 22; +} + +WebRtc_Word32 TraceWindows::AddBuildInfo(char* traceMessage) const +{ + // write data and time to text file + sprintf(traceMessage, "Build info: %s", BUILDINFO); + // Include NULL termination (hence + 1). + return static_cast<WebRtc_Word32>(strlen(traceMessage)+1); +} + +WebRtc_Word32 TraceWindows::AddDateTimeInfo(char* traceMessage) const +{ + _prevAPITickCount = timeGetTime(); + _prevTickCount = _prevAPITickCount; + + SYSTEMTIME sysTime; + GetLocalTime (&sysTime); + + TCHAR szDateStr[20]; + TCHAR szTimeStr[20]; + + // Create date string (e.g. Apr 04 2002) + GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, TEXT("MMM dd yyyy"), + szDateStr, 20); + + // Create time string (e.g. 15:32:08) + GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, TEXT("HH':'mm':'ss"), + szTimeStr, 20); + + sprintf(traceMessage, "Local Date: %s Local Time: %s", szDateStr, + szTimeStr); + + // Include NULL termination (hence + 1). + return static_cast<WebRtc_Word32>(strlen(traceMessage)+ 1); +} +} // namespace webrtc diff --git a/src/system_wrappers/source/trace_win.h b/src/system_wrappers/source/trace_win.h new file mode 100644 index 0000000000..803198e0fb --- /dev/null +++ b/src/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_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ + +#include "trace_impl.h" +#include <stdio.h> +#include <windows.h> + +namespace webrtc { +class TraceWindows : public TraceImpl +{ +public: + TraceWindows(); + virtual ~TraceWindows(); + + virtual WebRtc_Word32 AddTime(char* traceMessage, + const TraceLevel level) const; + + virtual WebRtc_Word32 AddBuildInfo(char* traceMessage) const; + virtual WebRtc_Word32 AddDateTimeInfo(char* traceMessage) const; +private: + volatile mutable WebRtc_UWord32 _prevAPITickCount; + volatile mutable WebRtc_UWord32 _prevTickCount; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ diff --git a/src/system_wrappers/source/unittest_utilities.h b/src/system_wrappers/source/unittest_utilities.h new file mode 100644 index 0000000000..771d798f5d --- /dev/null +++ b/src/system_wrappers/source/unittest_utilities.h @@ -0,0 +1,83 @@ +/* + * 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_UNITTEST_UTILITIES_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ + +// This file contains utilities that make it simpler to write unittests +// that are appropriate for the system_wrappers classes. + +#include <stdio.h> +#include <string.h> + +#include "system_wrappers/interface/trace.h" + +namespace webrtc { + +class TestTraceCallback : public TraceCallback { + public: + virtual void Print(const TraceLevel level, + const char* traceString, + const int length) { + if (traceString) { + char* cmd_print = new char[length+1]; + memcpy(cmd_print, traceString, length); + cmd_print[length] = '\0'; + printf("%s\n", cmd_print); + fflush(stdout); + delete[] cmd_print; + } + } +}; + +// A class that turns on tracing to stdout at the beginning of the test, +// and turns it off once the test is finished. +// Intended usage: +// class SomeTest : public ::testing::Test { +// protected: +// SomeTest() +// : trace_(false) {} // Change to true to turn on tracing. +// private: +// ScopedTracing trace_; +// } +class ScopedTracing { + public: + explicit ScopedTracing(bool logOn) { + logging_ = logOn; + StartTrace(); + } + + ~ScopedTracing() { + StopTrace(); + } + + private: + void StartTrace() { + if (logging_) { + Trace::CreateTrace(); + Trace::SetLevelFilter(webrtc::kTraceAll); + Trace::SetTraceCallback(&trace_); + } + } + + void StopTrace() { + if (logging_) { + Trace::ReturnTrace(); + } + } + + private: + bool logging_; + TestTraceCallback trace_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ diff --git a/src/system_wrappers/source/unittest_utilities_unittest.cc b/src/system_wrappers/source/unittest_utilities_unittest.cc new file mode 100644 index 0000000000..6e9a0c6186 --- /dev/null +++ b/src/system_wrappers/source/unittest_utilities_unittest.cc @@ -0,0 +1,34 @@ +/* + * 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 "system_wrappers/source/unittest_utilities.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/trace.h" + +namespace webrtc { + +// These tests merely check that the code compiles and that no +// fatal accidents happen when logging. +TEST(UnittestUtilities, TraceOn) { + ScopedTracing trace(true); + WEBRTC_TRACE(kTraceInfo, kTraceUtility, 0, "Log line that should appear"); + // TODO(hta): Verify that output appears. + // Note - output is written on another thread, so can take time to appear. +} + +TEST(UnittestUtilities, TraceOff) { + ScopedTracing trace(false); + WEBRTC_TRACE(kTraceInfo, kTraceUtility, 0, + "Log line that should not appear"); + // TODO(hta): Verify that no output appears. +} + +} // namespace webrtc |