Reformatted thread and static_instance.

BUG=
TEST=Trybots.

Review URL: https://webrtc-codereview.appspot.com/1006005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@3324 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
phoglund@webrtc.org 2013-01-02 08:45:03 +00:00
parent a19d04e707
commit ec9c942e45
9 changed files with 534 additions and 589 deletions

View File

@ -8,14 +8,14 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATICINSTANCETEMPLATE_H_ #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATICINSTANCETEMPLATE_H_ #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_
#include <assert.h> #include <assert.h>
#include "critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#ifdef _WIN32 #ifdef _WIN32
#include "fix_interlocked_exchange_pointer_win.h" #include "webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h"
#endif #endif
namespace webrtc { namespace webrtc {
@ -46,7 +46,7 @@ static T* GetStaticInstance(CountOperation count_operation) {
// reclaimed by the OS and memory leak tools will not recognize memory // reclaimed by the OS and memory leak tools will not recognize memory
// reachable from statics leaked so no noise is added by doing this. // reachable from statics leaked so no noise is added by doing this.
static CriticalSectionWrapper* crit_sect( static CriticalSectionWrapper* crit_sect(
CriticalSectionWrapper::CreateCriticalSection()); CriticalSectionWrapper::CreateCriticalSection());
CriticalSectionScoped lock(crit_sect); CriticalSectionScoped lock(crit_sect);
if (count_operation == if (count_operation ==
@ -116,8 +116,8 @@ static T* GetStaticInstance(CountOperation count_operation) {
} }
} }
} else { } else {
int newValue = InterlockedDecrement(&instance_count); int new_value = InterlockedDecrement(&instance_count);
if (newValue == 0) { if (new_value == 0) {
state = kDestroy; state = kDestroy;
} }
} }
@ -128,7 +128,7 @@ static T* GetStaticInstance(CountOperation count_operation) {
// local copy. // local copy.
T* new_instance = T::CreateInstance(); T* new_instance = T::CreateInstance();
if (1 == InterlockedIncrement(&instance_count)) { if (1 == InterlockedIncrement(&instance_count)) {
InterlockedExchangePointer(reinterpret_cast<void* volatile*>(&instance), InterlockedExchangePointer(reinterpret_cast<void * volatile*>(&instance),
new_instance); new_instance);
} else { } else {
InterlockedDecrement(&instance_count); InterlockedDecrement(&instance_count);
@ -137,8 +137,8 @@ static T* GetStaticInstance(CountOperation count_operation) {
} }
} }
} else if (state == kDestroy) { } else if (state == kDestroy) {
T* old_value = static_cast<T*> (InterlockedExchangePointer( T* old_value = static_cast<T*>(InterlockedExchangePointer(
reinterpret_cast<void* volatile*>(&instance), NULL)); reinterpret_cast<void * volatile*>(&instance), NULL));
if (old_value) { if (old_value) {
delete static_cast<T*>(old_value); delete static_cast<T*>(old_value);
} }
@ -150,4 +150,4 @@ static T* GetStaticInstance(CountOperation count_operation) {
} // namspace webrtc } // namspace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATICINSTANCETEMPLATE_H_ #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_

View File

@ -16,10 +16,11 @@
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_
#include "common_types.h" #include "webrtc/common_types.h"
#include "typedefs.h" #include "webrtc/typedefs.h"
namespace webrtc { namespace webrtc {
// Object that will be passed by the spawned thread when it enters the callback // Object that will be passed by the spawned thread when it enters the callback
// function. // function.
#define ThreadObj void* #define ThreadObj void*
@ -27,68 +28,67 @@ namespace webrtc {
// Callback function that the spawned thread will enter once spawned. // Callback function that the spawned thread will enter once spawned.
// A return value of false is interpreted as that the function has no // A return value of false is interpreted as that the function has no
// more work to do and that the thread can be released. // more work to do and that the thread can be released.
typedef bool(*ThreadRunFunction)(ThreadObj); typedef bool(*ThreadRunFunction)(ThreadObj);
enum ThreadPriority enum ThreadPriority {
{ kLowPriority = 1,
kLowPriority = 1, kNormalPriority = 2,
kNormalPriority = 2, kHighPriority = 3,
kHighPriority = 3, kHighestPriority = 4,
kHighestPriority = 4, kRealtimePriority = 5
kRealtimePriority = 5
}; };
class ThreadWrapper class ThreadWrapper {
{ public:
public: enum {kThreadMaxNameLength = 64};
enum {kThreadMaxNameLength = 64};
virtual ~ThreadWrapper() {}; virtual ~ThreadWrapper() {};
// Factory method. Constructor disabled. // Factory method. Constructor disabled.
// //
// func Pointer to a, by user, specified callback function. // func Pointer to a, by user, specified callback function.
// obj Object associated with the thread. Passed in the callback // obj Object associated with the thread. Passed in the callback
// function. // function.
// prio Thread priority. May require root/admin rights. // prio Thread priority. May require root/admin rights.
// threadName NULL terminated thread name, will be visable in the Windows // thread_name NULL terminated thread name, will be visable in the Windows
// debugger. // debugger.
static ThreadWrapper* CreateThread(ThreadRunFunction func = 0, static ThreadWrapper* CreateThread(ThreadRunFunction func = 0,
ThreadObj obj= 0, ThreadObj obj = 0,
ThreadPriority prio = kNormalPriority, ThreadPriority prio = kNormalPriority,
const char* threadName = 0); const char* thread_name = 0);
// Get the current thread's kernel thread ID. // Get the current thread's kernel thread ID.
static uint32_t GetThreadId(); static uint32_t GetThreadId();
// Non blocking termination of the spawned thread. Note that it is not safe // Non blocking termination of the spawned thread. Note that it is not safe
// to delete this class until the spawned thread has been reclaimed. // to delete this class until the spawned thread has been reclaimed.
virtual void SetNotAlive() = 0; virtual void SetNotAlive() = 0;
// Tries to spawns a thread and returns true if that was successful. // Tries to spawns a thread and returns true if that was successful.
// Additionally, it tries to set thread priority according to the priority // Additionally, it tries to set thread priority according to the priority
// from when CreateThread was called. However, failure to set priority will // from when CreateThread was called. However, failure to set priority will
// not result in a false return value. // not result in a false return value.
// TODO(henrike): add a function for polling whether priority was set or // TODO(henrike): add a function for polling whether priority was set or
// not. // not.
virtual bool Start(unsigned int& id) = 0; virtual bool Start(unsigned int& id) = 0;
// Sets the threads CPU affinity. CPUs are listed 0 - (number of CPUs - 1). // Sets the threads CPU affinity. CPUs are listed 0 - (number of CPUs - 1).
// The numbers in processorNumbers specify which CPUs are allowed to run the // The numbers in processor_numbers specify which CPUs are allowed to run the
// thread. processorNumbers should not contain any duplicates and elements // thread. processor_numbers should not contain any duplicates and elements
// should be lower than (number of CPUs - 1). amountOfProcessors should be // should be lower than (number of CPUs - 1). amount_of_processors should be
// equal to the number of processors listed in processorNumbers // equal to the number of processors listed in processor_numbers.
virtual bool SetAffinity(const int* /*processorNumbers*/, virtual bool SetAffinity(const int* processor_numbers,
const unsigned int /*amountOfProcessors*/) { const unsigned int amount_of_processors) {
return false; return false;
} }
// Stops the spawned thread and waits for it to be reclaimed with a timeout // 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. // of two seconds. Will return false if the thread was not reclaimed.
// Multiple tries to Stop are allowed (e.g. to wait longer than 2 seconds). // Multiple tries to Stop are allowed (e.g. to wait longer than 2 seconds).
// It's ok to call Stop() even if the spawned thread has been reclaimed. // It's ok to call Stop() even if the spawned thread has been reclaimed.
virtual bool Stop() = 0; virtual bool Stop() = 0;
}; };
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_

View File

@ -8,23 +8,24 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "thread_wrapper.h" #include "webrtc/system_wrappers/interface/thread_wrapper.h"
#if defined(_WIN32) #if defined(_WIN32)
#include "thread_win.h" #include "webrtc/system_wrappers/source/thread_win.h"
#else #else
#include "thread_posix.h" #include "webrtc/system_wrappers/source/thread_posix.h"
#endif #endif
namespace webrtc { namespace webrtc {
ThreadWrapper* ThreadWrapper::CreateThread(ThreadRunFunction func, ThreadWrapper* ThreadWrapper::CreateThread(ThreadRunFunction func,
ThreadObj obj, ThreadPriority prio, ThreadObj obj, ThreadPriority prio,
const char* threadName) const char* thread_name) {
{
#if defined(_WIN32) #if defined(_WIN32)
return new ThreadWindows(func, obj, prio, threadName); return new ThreadWindows(func, obj, prio, thread_name);
#else #else
return ThreadPosix::Create(func, obj, prio, threadName); return ThreadPosix::Create(func, obj, prio, thread_name);
#endif #endif
} }
} // namespace webrtc } // namespace webrtc

View File

@ -9,47 +9,47 @@
*/ */
// The state of a thread is controlled by the two member variables // The state of a thread is controlled by the two member variables
// _alive and _dead. // alive_ and dead_.
// _alive represents the state the thread has been ordered to achieve. // 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 // It is set to true by the thread at startup, and is set to false by
// other threads, using SetNotAlive() and Stop(). // other threads, using SetNotAlive() and Stop().
// _dead represents the state the thread has achieved. // dead_ represents the state the thread has achieved.
// It is written by the thread encapsulated by this class only // It is written by the thread encapsulated by this class only
// (except at init). It is read only by the Stop() method. // (except at init). It is read only by the Stop() method.
// The Run() method fires _event when it's started; this ensures that the // The Run() method fires event_ when it's started; this ensures that the
// Start() method does not continue until after _dead is false. // Start() method does not continue until after dead_ is false.
// This protects against premature Stop() calls from the creator thread, but // This protects against premature Stop() calls from the creator thread, but
// not from other threads. // not from other threads.
// Their transitions and states: // Their transitions and states:
// _alive _dead Set by // alive_ dead_ Set by
// false true Constructor // false true Constructor
// true false Run() method entry // true false Run() method entry
// false any Run() method runFunction failure // false any Run() method run_function failure
// any false Run() method exit (happens only with _alive false) // any false Run() method exit (happens only with alive_ false)
// false any SetNotAlive // false any SetNotAlive
// false any Stop Stop waits for _dead to become true. // false any Stop Stop waits for dead_ to become true.
// //
// Summarized a different way: // Summarized a different way:
// Variable Writer Reader // Variable Writer Reader
// _alive Constructor(false) Run.loop // alive_ Constructor(false) Run.loop
// Run.start(true) // Run.start(true)
// Run.fail(false) // Run.fail(false)
// SetNotAlive(false) // SetNotAlive(false)
// Stop(false) // Stop(false)
// //
// _dead Constructor(true) Stop.loop // dead_ Constructor(true) Stop.loop
// Run.start(false) // Run.start(false)
// Run.exit(true) // Run.exit(true)
#include "thread_posix.h" #include "webrtc/system_wrappers/source/thread_posix.h"
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <string.h> // strncpy #include <string.h> // strncpy
#include <time.h> // nanosleep #include <time.h> // nanosleep
#include <unistd.h> #include <unistd.h>
#ifdef WEBRTC_LINUX #ifdef WEBRTC_LINUX
#include <sys/types.h> #include <sys/types.h>
@ -59,86 +59,81 @@
#include <sys/prctl.h> #include <sys/prctl.h>
#endif #endif
#include "system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/event_wrapper.h" #include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "system_wrappers/interface/trace.h" #include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc { namespace webrtc {
int ConvertToSystemPriority(ThreadPriority priority, int minPrio, int maxPrio) int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
{ int max_prio) {
assert(maxPrio - minPrio > 2); assert(max_prio - min_prio > 2);
const int topPrio = maxPrio - 1; const int top_prio = max_prio - 1;
const int lowPrio = minPrio + 1; const int low_prio = min_prio + 1;
switch (priority) switch (priority) {
{
case kLowPriority: case kLowPriority:
return lowPrio; return low_prio;
case kNormalPriority: case kNormalPriority:
// The -1 ensures that the kHighPriority is always greater or equal to // The -1 ensures that the kHighPriority is always greater or equal to
// kNormalPriority. // kNormalPriority.
return (lowPrio + topPrio - 1) / 2; return (low_prio + top_prio - 1) / 2;
case kHighPriority: case kHighPriority:
return std::max(topPrio - 2, lowPrio); return std::max(top_prio - 2, low_prio);
case kHighestPriority: case kHighestPriority:
return std::max(topPrio - 1, lowPrio); return std::max(top_prio - 1, low_prio);
case kRealtimePriority: case kRealtimePriority:
return topPrio; return top_prio;
} }
assert(false); assert(false);
return lowPrio; return low_prio;
} }
extern "C" extern "C"
{ {
static void* StartThread(void* lpParameter) static void* StartThread(void* lp_parameter) {
{ static_cast<ThreadPosix*>(lp_parameter)->Run();
static_cast<ThreadPosix*>(lpParameter)->Run(); return 0;
return 0; }
}
} }
ThreadWrapper* ThreadPosix::Create(ThreadRunFunction func, ThreadObj obj, ThreadWrapper* ThreadPosix::Create(ThreadRunFunction func,
ThreadPriority prio, const char* threadName) ThreadObj obj,
{ ThreadPriority prio,
ThreadPosix* ptr = new ThreadPosix(func, obj, prio, threadName); const char* thread_name) {
if (!ptr) ThreadPosix* ptr = new ThreadPosix(func, obj, prio, thread_name);
{ if (!ptr) {
return NULL; return NULL;
} }
const int error = ptr->Construct(); const int error = ptr->Construct();
if (error) if (error) {
{ delete ptr;
delete ptr; return NULL;
return NULL; }
} return ptr;
return ptr;
} }
ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj, ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj,
ThreadPriority prio, const char* threadName) ThreadPriority prio, const char* thread_name)
: _runFunction(func), : run_function_(func),
_obj(obj), obj_(obj),
_crit_state(CriticalSectionWrapper::CreateCriticalSection()), crit_state_(CriticalSectionWrapper::CreateCriticalSection()),
_alive(false), alive_(false),
_dead(true), dead_(true),
_prio(prio), prio_(prio),
_event(EventWrapper::Create()), event_(EventWrapper::Create()),
_name(), name_(),
_setThreadName(false), set_thread_name_(false),
#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) #if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID))
_pid(-1), pid_(-1),
#endif #endif
_attr(), attr_(),
_thread(0) thread_(0) {
{ if (thread_name != NULL) {
if (threadName != NULL) set_thread_name_ = true;
{ strncpy(name_, thread_name, kThreadMaxNameLength);
_setThreadName = true; name_[kThreadMaxNameLength - 1] = '\0';
strncpy(_name, threadName, kThreadMaxNameLength); }
_name[kThreadMaxNameLength - 1] = '\0';
}
} }
uint32_t ThreadWrapper::GetThreadId() { uint32_t ThreadWrapper::GetThreadId() {
@ -149,132 +144,120 @@ uint32_t ThreadWrapper::GetThreadId() {
#endif #endif
} }
int ThreadPosix::Construct() int ThreadPosix::Construct() {
{ int result = 0;
int result = 0;
#if !defined(WEBRTC_ANDROID) #if !defined(WEBRTC_ANDROID)
// Enable immediate cancellation if requested, see Shutdown() // Enable immediate cancellation if requested, see Shutdown().
result = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); result = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (result != 0) if (result != 0) {
{ return -1;
return -1; }
} result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
result = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); if (result != 0) {
if (result != 0) return -1;
{ }
return -1;
}
#endif #endif
result = pthread_attr_init(&_attr); result = pthread_attr_init(&attr_);
if (result != 0) if (result != 0) {
{ return -1;
return -1; }
} return 0;
return 0;
} }
ThreadPosix::~ThreadPosix() ThreadPosix::~ThreadPosix() {
{ pthread_attr_destroy(&attr_);
pthread_attr_destroy(&_attr); delete event_;
delete _event; delete crit_state_;
delete _crit_state;
} }
#define HAS_THREAD_ID !defined(WEBRTC_IOS) && !defined(WEBRTC_MAC) #define HAS_THREAD_ID !defined(WEBRTC_IOS) && !defined(WEBRTC_MAC)
#if HAS_THREAD_ID
bool ThreadPosix::Start(unsigned int& threadID) bool ThreadPosix::Start(unsigned int& thread_id)
#else
bool ThreadPosix::Start(unsigned int& /*threadID*/)
#endif
{ {
if (!_runFunction) if (!run_function_) {
{ return false;
return false; }
} int result = pthread_attr_setdetachstate(&attr_, PTHREAD_CREATE_DETACHED);
int result = pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_DETACHED); // Set the stack stack size to 1M.
// Set the stack stack size to 1M. result |= pthread_attr_setstacksize(&attr_, 1024 * 1024);
result |= pthread_attr_setstacksize(&_attr, 1024*1024);
#ifdef WEBRTC_THREAD_RR #ifdef WEBRTC_THREAD_RR
const int policy = SCHED_RR; const int policy = SCHED_RR;
#else #else
const int policy = SCHED_FIFO; const int policy = SCHED_FIFO;
#endif #endif
_event->Reset(); event_->Reset();
// If pthread_create was successful, a thread was created and is running. // If pthread_create was successful, a thread was created and is running.
// Don't return false if it was successful since if there are any other // Don't return false if it was successful since if there are any other
// failures the state will be: thread was started but not configured as // failures the state will be: thread was started but not configured as
// asked for. However, the caller of this API will assume that a false // asked for. However, the caller of this API will assume that a false
// return value means that the thread never started. // return value means that the thread never started.
result |= pthread_create(&_thread, &_attr, &StartThread, this); result |= pthread_create(&thread_, &attr_, &StartThread, this);
if (result != 0) if (result != 0) {
{ return false;
return false; }
}
// Wait up to 10 seconds for the OS to call the callback function. Prevents // Wait up to 10 seconds for the OS to call the callback function. Prevents
// race condition if Stop() is called too quickly after start. // race condition if Stop() is called too quickly after start.
if (kEventSignaled != _event->Wait(WEBRTC_EVENT_10_SEC)) if (kEventSignaled != event_->Wait(WEBRTC_EVENT_10_SEC)) {
{ WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
WEBRTC_TRACE(kTraceError, kTraceUtility, -1, "posix thread event never triggered");
"posix thread event never triggered");
// Timed out. Something went wrong. // Timed out. Something went wrong.
_runFunction = NULL; run_function_ = NULL;
return true; return true;
} }
#if HAS_THREAD_ID #if HAS_THREAD_ID
threadID = static_cast<unsigned int>(_thread); thread_id = static_cast<unsigned int>(thread_);
#endif #endif
sched_param param; sched_param param;
const int minPrio = sched_get_priority_min(policy); const int min_prio = sched_get_priority_min(policy);
const int maxPrio = sched_get_priority_max(policy); const int max_prio = sched_get_priority_max(policy);
if ((minPrio == EINVAL) || (maxPrio == EINVAL))
{ if ((min_prio == EINVAL) || (max_prio == EINVAL)) {
WEBRTC_TRACE(kTraceError, kTraceUtility, -1, WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
"unable to retreive min or max priority for threads"); "unable to retreive min or max priority for threads");
return true;
}
if (maxPrio - minPrio <= 2)
{
// There is no room for setting priorities with any granularity.
return true;
}
param.sched_priority = ConvertToSystemPriority(_prio, minPrio, maxPrio);
result = pthread_setschedparam(_thread, policy, &param);
if (result == EINVAL)
{
WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
"unable to set thread priority");
}
return true; return true;
}
if (max_prio - min_prio <= 2) {
// There is no room for setting priorities with any granularity.
return true;
}
param.sched_priority = ConvertToSystemPriority(prio_, min_prio, max_prio);
result = pthread_setschedparam(thread_, policy, &param);
if (result == EINVAL) {
WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
"unable to set thread priority");
}
return true;
} }
// CPU_ZERO and CPU_SET are not available in NDK r7, so disable // CPU_ZERO and CPU_SET are not available in NDK r7, so disable
// SetAffinity on Android for now. // SetAffinity on Android for now.
#if (defined(WEBRTC_LINUX) && (!defined(WEBRTC_ANDROID))) #if (defined(WEBRTC_LINUX) && (!defined(WEBRTC_ANDROID)))
bool ThreadPosix::SetAffinity(const int* processorNumbers, bool ThreadPosix::SetAffinity(const int* processor_numbers,
const unsigned int amountOfProcessors) { const unsigned int amount_of_processors) {
if (!processorNumbers || (amountOfProcessors == 0)) { if (!processor_numbers || (amount_of_processors == 0)) {
return false; return false;
} }
cpu_set_t mask; cpu_set_t mask;
CPU_ZERO(&mask); CPU_ZERO(&mask);
for (unsigned int processor = 0; for (unsigned int processor = 0;
processor < amountOfProcessors; processor < amount_of_processors;
processor++) { ++processor) {
CPU_SET(processorNumbers[processor], &mask); CPU_SET(processor_numbers[processor], &mask);
} }
#if defined(WEBRTC_ANDROID) #if defined(WEBRTC_ANDROID)
// Android. // Android.
const int result = syscall(__NR_sched_setaffinity, const int result = syscall(__NR_sched_setaffinity,
_pid, pid_,
sizeof(mask), sizeof(mask),
&mask); &mask);
#else #else
// "Normal" Linux. // "Normal" Linux.
const int result = sched_setaffinity(_pid, const int result = sched_setaffinity(pid_,
sizeof(mask), sizeof(mask),
&mask); &mask);
#endif #endif
@ -288,118 +271,99 @@ bool ThreadPosix::SetAffinity(const int* processorNumbers,
// NOTE: On Mac OS X, use the Thread affinity API in // NOTE: On Mac OS X, use the Thread affinity API in
// /usr/include/mach/thread_policy.h: thread_policy_set and mach_thread_self() // /usr/include/mach/thread_policy.h: thread_policy_set and mach_thread_self()
// instead of Linux gettid() syscall. // instead of Linux gettid() syscall.
bool ThreadPosix::SetAffinity(const int* , const unsigned int) bool ThreadPosix::SetAffinity(const int* , const unsigned int) {
{ return false;
}
#endif
void ThreadPosix::SetNotAlive() {
CriticalSectionScoped cs(crit_state_);
alive_ = false;
}
bool ThreadPosix::Stop() {
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++) {
timespec t;
t.tv_sec = 0;
t.tv_nsec = 10 * 1000 * 1000;
nanosleep(&t, NULL);
{
CriticalSectionScoped cs(crit_state_);
dead = dead_;
}
}
if (dead) {
return true;
} else {
return false; return false;
} }
#endif
void ThreadPosix::SetNotAlive()
{
CriticalSectionScoped cs(_crit_state);
_alive = false;
} }
bool ThreadPosix::Stop() void ThreadPosix::Run() {
{ {
bool dead = false; CriticalSectionScoped cs(crit_state_);
{ alive_ = true;
CriticalSectionScoped cs(_crit_state); dead_ = false;
_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++)
{
timespec t;
t.tv_sec = 0;
t.tv_nsec = 10*1000*1000;
nanosleep(&t, NULL);
{
CriticalSectionScoped cs(_crit_state);
dead = _dead;
}
}
if (dead)
{
return true;
}
else
{
return false;
}
}
void ThreadPosix::Run()
{
{
CriticalSectionScoped cs(_crit_state);
_alive = true;
_dead = false;
}
#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) #if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID))
_pid = GetThreadId(); pid_ = GetThreadId();
#endif #endif
// The event the Start() is waiting for. // The event the Start() is waiting for.
_event->Set(); event_->Set();
if (_setThreadName) if (set_thread_name_) {
{
#ifdef WEBRTC_LINUX #ifdef WEBRTC_LINUX
prctl(PR_SET_NAME, (unsigned long)_name, 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)name_, 0, 0, 0);
#endif #endif
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
"Thread with name:%s started ", _name); "Thread with name:%s started ", name_);
} else } else {
{ WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Thread without name started");
"Thread without name started"); }
bool alive = true;
do {
if (run_function_) {
if (!run_function_(obj_)) {
alive = false;
}
} else {
alive = false;
} }
bool alive = true;
do
{ {
if (_runFunction) CriticalSectionScoped cs(crit_state_);
{ if (!alive) {
if (!_runFunction(_obj)) alive_ = false;
{ }
alive = false; alive = alive_;
}
}
else
{
alive = false;
}
{
CriticalSectionScoped cs(_crit_state);
if (!alive) {
_alive = false;
}
alive = _alive;
}
} }
while (alive); } while (alive);
if (_setThreadName) if (set_thread_name_) {
{ // Don't set the name for the trace thread because it may cause a
// Don't set the name for the trace thread because it may cause a // deadlock. TODO(hellner) there should be a better solution than
// deadlock. TODO (hellner) there should be a better solution than // coupling the thread and the trace class like this.
// coupling the thread and the trace class like this. if (strcmp(name_, "Trace")) {
if (strcmp(_name, "Trace")) WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
{ "Thread with name:%s stopped", name_);
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
"Thread with name:%s stopped", _name);
}
}
else
{
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
"Thread without name stopped");
}
{
CriticalSectionScoped cs(_crit_state);
_dead = true;
} }
} else {
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
"Thread without name stopped");
}
{
CriticalSectionScoped cs(crit_state_);
dead_ = true;
}
} }
} // namespace webrtc } // namespace webrtc

View File

@ -11,7 +11,8 @@
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_ #ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_ #define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_
#include "thread_wrapper.h" #include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include <pthread.h> #include <pthread.h>
namespace webrtc { namespace webrtc {
@ -19,54 +20,54 @@ namespace webrtc {
class CriticalSectionWrapper; class CriticalSectionWrapper;
class EventWrapper; class EventWrapper;
int ConvertToSystemPriority(ThreadPriority priority, int minPrio, int maxPrio); int ConvertToSystemPriority(ThreadPriority priority, int min_prio,
int max_prio);
class ThreadPosix : public ThreadWrapper class ThreadPosix : public ThreadWrapper {
{ public:
public: static ThreadWrapper* Create(ThreadRunFunction func, ThreadObj obj,
static ThreadWrapper* Create(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, const char* thread_name);
ThreadPriority prio, const char* threadName);
ThreadPosix(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, ThreadPosix(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio,
const char* threadName); const char* thread_name);
~ThreadPosix(); ~ThreadPosix();
// From ThreadWrapper // From ThreadWrapper.
virtual void SetNotAlive(); virtual void SetNotAlive();
virtual bool Start(unsigned int& id); virtual bool Start(unsigned int& id);
// Not implemented on Mac // Not implemented on Mac.
virtual bool SetAffinity(const int* processorNumbers, virtual bool SetAffinity(const int* processor_numbers,
unsigned int amountOfProcessors); unsigned int amount_of_processors);
virtual bool Stop(); virtual bool Stop();
void Run(); void Run();
private: private:
int Construct(); int Construct();
private: private:
// processing function ThreadRunFunction run_function_;
ThreadRunFunction _runFunction; ThreadObj obj_;
ThreadObj _obj;
// internal state // Internal state.
CriticalSectionWrapper* _crit_state; // Protects _alive and _dead CriticalSectionWrapper* crit_state_; // Protects alive_ and dead_
bool _alive; bool alive_;
bool _dead; bool dead_;
ThreadPriority _prio; ThreadPriority prio_;
EventWrapper* _event; EventWrapper* event_;
// zero-terminated thread name string // Zero-terminated thread name string.
char _name[kThreadMaxNameLength]; char name_[kThreadMaxNameLength];
bool _setThreadName; bool set_thread_name_;
// handle to thread // Handle to thread.
#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) #if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID))
pid_t _pid; pid_t pid_;
#endif #endif
pthread_attr_t _attr; pthread_attr_t attr_;
pthread_t _thread; pthread_t thread_;
}; };
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_ #endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_POSIX_H_

View File

@ -8,12 +8,12 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "system_wrappers/source/thread_posix.h" #include "webrtc/system_wrappers/source/thread_posix.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
TEST(ThreadTestPosix, PrioritySettings) { TEST(ThreadTestPosix, PrioritySettings) {
// API assumes that maxPrio - minPrio > 2. Test the extreme case. // API assumes that max_prio - min_prio > 2. Test the extreme case.
const int kMinPrio = -1; const int kMinPrio = -1;
const int kMaxPrio = 2; const int kMaxPrio = 2;

View File

@ -8,22 +8,22 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "system_wrappers/interface/thread_wrapper.h" #include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc { namespace webrtc {
TEST(ThreadTest, NullFunctionPointer) { TEST(ThreadTest, NullFunctionPointer) {
webrtc::scoped_ptr<ThreadWrapper> thread( webrtc::scoped_ptr<ThreadWrapper> thread(
webrtc::ThreadWrapper::CreateThread()); webrtc::ThreadWrapper::CreateThread());
unsigned int id = 42; unsigned int id = 42;
EXPECT_FALSE(thread->Start(id)); EXPECT_FALSE(thread->Start(id));
} }
// Function that does nothing, and reports success. // Function that does nothing, and reports success.
bool NullRunFunction(void* /* obj */) { bool NullRunFunction(void* obj) {
return true; return true;
} }
@ -37,7 +37,7 @@ TEST(ThreadTest, StartStop) {
// Function that sets a boolean. // Function that sets a boolean.
bool SetFlagRunFunction(void* obj) { bool SetFlagRunFunction(void* obj) {
bool* obj_as_bool = static_cast<bool*> (obj); bool* obj_as_bool = static_cast<bool*>(obj);
*obj_as_bool = true; *obj_as_bool = true;
return true; return true;
} }
@ -48,8 +48,10 @@ TEST(ThreadTest, RunFunctionIsCalled) {
&flag); &flag);
unsigned int id = 42; unsigned int id = 42;
ASSERT_TRUE(thread->Start(id)); ASSERT_TRUE(thread->Start(id));
// At this point, the flag may be either true or false. // At this point, the flag may be either true or false.
EXPECT_TRUE(thread->Stop()); EXPECT_TRUE(thread->Stop());
// We expect the thread to have run at least once. // We expect the thread to have run at least once.
EXPECT_TRUE(flag); EXPECT_TRUE(flag);
delete thread; delete thread;

View File

@ -8,215 +8,191 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include "thread_win.h" #include "webrtc/system_wrappers/source/thread_win.h"
#include <assert.h> #include <assert.h>
#include <process.h> #include <process.h>
#include <stdio.h> #include <stdio.h>
#include <windows.h> #include <windows.h>
#include "set_thread_name_win.h" #include "webrtc/system_wrappers/interface/trace.h"
#include "trace.h" #include "webrtc/system_wrappers/source/set_thread_name_win.h"
namespace webrtc { namespace webrtc {
ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj, ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj,
ThreadPriority prio, const char* threadName) ThreadPriority prio, const char* thread_name)
: ThreadWrapper(), : ThreadWrapper(),
_runFunction(func), run_function_(func),
_obj(obj), obj_(obj),
_alive(false), alive_(false),
_dead(true), dead_(true),
_doNotCloseHandle(false), do_not_close_handle_(false),
_prio(prio), prio_(prio),
_event(NULL), event_(NULL),
_thread(NULL), thread_(NULL),
_id(0), id_(0),
_name(), name_(),
_setThreadName(false) set_thread_name_(false) {
{ event_ = EventWrapper::Create();
_event = EventWrapper::Create(); critsect_stop_ = CriticalSectionWrapper::CreateCriticalSection();
_critsectStop = CriticalSectionWrapper::CreateCriticalSection(); if (thread_name != NULL) {
if (threadName != NULL) // Set the thread name to appear in the VS debugger.
{ set_thread_name_ = true;
// Set the thread name to appear in the VS debugger. strncpy(name_, thread_name, kThreadMaxNameLength);
_setThreadName = true; }
strncpy(_name, threadName, kThreadMaxNameLength);
}
} }
ThreadWindows::~ThreadWindows() ThreadWindows::~ThreadWindows() {
{
#ifdef _DEBUG #ifdef _DEBUG
assert(!_alive); assert(!alive_);
#endif #endif
if (_thread) if (thread_) {
{ CloseHandle(thread_);
CloseHandle(_thread); }
} if (event_) {
if(_event) delete event_;
{ }
delete _event; if (critsect_stop_) {
} delete critsect_stop_;
if(_critsectStop) }
{
delete _critsectStop;
}
} }
uint32_t ThreadWrapper::GetThreadId() { uint32_t ThreadWrapper::GetThreadId() {
return GetCurrentThreadId(); return GetCurrentThreadId();
} }
unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter) unsigned int WINAPI ThreadWindows::StartThread(LPVOID lp_parameter) {
{ static_cast<ThreadWindows*>(lp_parameter)->Run();
static_cast<ThreadWindows*>(lpParameter)->Run(); return 0;
return 0;
} }
bool ThreadWindows::Start(unsigned int& threadID) bool ThreadWindows::Start(unsigned int& thread_id) {
{ if (!run_function_) {
if (!_runFunction) { return false;
return false; }
} do_not_close_handle_ = false;
_doNotCloseHandle = false;
// Set stack size to 1M // Set stack size to 1M
_thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0, thread_ = (HANDLE)_beginthreadex(NULL, 1024 * 1024, StartThread, (void*)this,
&threadID); 0, &thread_id);
if(_thread == NULL) if (thread_ == NULL) {
{ return false;
return false; }
} id_ = thread_id;
_id = threadID; event_->Wait(INFINITE);
_event->Wait(INFINITE);
switch(_prio) switch (prio_) {
{
case kLowPriority: case kLowPriority:
SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL); SetThreadPriority(thread_, THREAD_PRIORITY_BELOW_NORMAL);
break; break;
case kNormalPriority: case kNormalPriority:
SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL); SetThreadPriority(thread_, THREAD_PRIORITY_NORMAL);
break; break;
case kHighPriority: case kHighPriority:
SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL); SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
break; break;
case kHighestPriority: case kHighestPriority:
SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST); SetThreadPriority(thread_, THREAD_PRIORITY_HIGHEST);
break; break;
case kRealtimePriority: case kRealtimePriority:
SetThreadPriority(_thread, THREAD_PRIORITY_TIME_CRITICAL); SetThreadPriority(thread_, THREAD_PRIORITY_TIME_CRITICAL);
break; break;
}; };
return true;
}
bool ThreadWindows::SetAffinity(const int* processor_numbers,
const unsigned int amount_of_processors) {
DWORD_PTR processor_bit_mask = 0;
for (unsigned int processor_index = 0;
processor_index < amount_of_processors;
++processor_index) {
// 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 |=
processor_bit_mask = 1 << processor_numbers[processor_index];
}
return SetThreadAffinityMask(thread_, processor_bit_mask) != 0;
}
void ThreadWindows::SetNotAlive() {
alive_ = false;
}
bool ThreadWindows::Stop() {
critsect_stop_->Enter();
// Prevents the handle from being closed in ThreadWindows::Run()
do_not_close_handle_ = true;
alive_ = false;
bool signaled = false;
if (thread_ && !dead_) {
critsect_stop_->Leave();
// Wait up to 2 seconds for the thread to complete.
if (WAIT_OBJECT_0 == WaitForSingleObject(thread_, 2000)) {
signaled = true;
}
critsect_stop_->Enter();
}
if (thread_) {
CloseHandle(thread_);
thread_ = NULL;
}
critsect_stop_->Leave();
if (dead_ || signaled) {
return true; return true;
} else {
return false;
}
} }
bool ThreadWindows::SetAffinity(const int* processorNumbers, void ThreadWindows::Run() {
const unsigned int amountOfProcessors) alive_ = true;
{ dead_ = false;
DWORD_PTR processorBitMask = 0; event_->Set();
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() // All tracing must be after event_->Set to avoid deadlock in Trace.
{ if (set_thread_name_) {
_alive = false; 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");
}
bool ThreadWindows::Stop() do {
{ if (run_function_) {
_critsectStop->Enter(); if (!run_function_(obj_)) {
// Prevents the handle from being closed in ThreadWindows::Run() alive_ = false;
_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 { } else {
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id, alive_ = false;
"Thread without name stopped");
} }
} while (alive_);
_critsectStop->Enter(); if (set_thread_name_) {
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
"Thread with name:%s stopped", name_);
} else {
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, id_,
"Thread without name stopped");
}
if (_thread && !_doNotCloseHandle) critsect_stop_->Enter();
{
HANDLE thread = _thread;
_thread = NULL;
CloseHandle(thread);
}
_dead = true;
_critsectStop->Leave(); if (thread_ && !do_not_close_handle_) {
HANDLE thread = thread_;
thread_ = NULL;
CloseHandle(thread);
}
dead_ = true;
critsect_stop_->Leave();
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -8,57 +8,58 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ #ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ #define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_
#include "thread_wrapper.h" #include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "event_wrapper.h"
#include "critical_section_wrapper.h"
#include <windows.h> #include <windows.h>
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
namespace webrtc { namespace webrtc {
class ThreadWindows : public ThreadWrapper class ThreadWindows : public ThreadWrapper {
{ public:
public: ThreadWindows(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio,
ThreadWindows(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, const char* thread_name);
const char* threadName); virtual ~ThreadWindows();
virtual ~ThreadWindows();
virtual bool Start(unsigned int& id); virtual bool Start(unsigned int& id);
bool SetAffinity(const int* processorNumbers, bool SetAffinity(const int* processor_numbers,
const unsigned int amountOfProcessors); const unsigned int amount_of_processors);
virtual bool Stop(); virtual bool Stop();
virtual void SetNotAlive(); virtual void SetNotAlive();
static unsigned int WINAPI StartThread(LPVOID lpParameter); static unsigned int WINAPI StartThread(LPVOID lp_parameter);
protected: protected:
virtual void Run(); virtual void Run();
private: private:
ThreadRunFunction _runFunction; ThreadRunFunction run_function_;
ThreadObj _obj; ThreadObj obj_;
bool _alive; bool alive_;
bool _dead; bool dead_;
// TODO (hellner) // TODO(hellner)
// _doNotCloseHandle member seem pretty redundant. Should be able to remove // do_not_close_handle_ member seem pretty redundant. Should be able to remove
// it. Basically it should be fine to reclaim the handle when calling stop // it. Basically it should be fine to reclaim the handle when calling stop
// and in the destructor. // and in the destructor.
bool _doNotCloseHandle; bool do_not_close_handle_;
ThreadPriority _prio; ThreadPriority prio_;
EventWrapper* _event; EventWrapper* event_;
CriticalSectionWrapper* _critsectStop; CriticalSectionWrapper* critsect_stop_;
HANDLE _thread; HANDLE thread_;
unsigned int _id; unsigned int id_;
char _name[kThreadMaxNameLength]; char name_[kThreadMaxNameLength];
bool _setThreadName; bool set_thread_name_;
}; };
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ #endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WIN_H_