diff --git a/src/core/thread.cpp b/src/core/thread.cpp new file mode 100644 index 00000000..3d37c580 --- /dev/null +++ b/src/core/thread.cpp @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include "thread.h" + +#ifndef NANOSECONDS_PER_SECOND +#define NANOSECONDS_PER_SECOND 1000000000 +#endif + +// Helper class for thread creation. +class ThreadStarter +{ +public: + ThreadStarter(Thread &thread) : m_thread(thread) {} + void operator()() + { + m_thread.MainWrapper(); + } + +private: + Thread &m_thread; +}; + +Thread::Thread() +: m_isTerminatedMutexLock(m_isTerminatedMutex), m_userReqTerminateLock(m_shouldTerminateMutex) +{ +} + +Thread::~Thread() +{ +} + +void +Thread::Run() +{ + // Create the boost thread object. + boost::mutex::scoped_lock threadLock(m_threadObjMutex); + + if (!m_threadObj.get()) + m_threadObj.reset(new boost::thread(ThreadStarter(*this))); +} + +void +Thread::SignalTermination() +{ + // Unlock the shouldTerminateMutex. + m_userReqTerminateLock.unlock(); +} + +bool +Thread::Join(unsigned msecTimeout) +{ + // Calculate time after timeout + boost::xtime t; + boost::xtime_get(&t, boost::TIME_UTC); + t.sec += msecTimeout / 1000; + t.nsec += (msecTimeout % 1000) * 1000; + if (t.nsec > NANOSECONDS_PER_SECOND) + { + t.sec++; + t.nsec -= NANOSECONDS_PER_SECOND; + } + + // Wait for the termination of the application code. + boost::timed_mutex::scoped_timed_lock lock(m_isTerminatedMutex, t); + bool tmpIsTerminated = lock.locked(); + + if (tmpIsTerminated) + { + boost::mutex::scoped_lock lock(m_threadObjMutex); + // Wait for "real" termination of the thread. + if (m_threadObj.get()) + { + m_threadObj->join(); + m_threadObj.reset(); + } + } + + return tmpIsTerminated; +} + +void +Thread::MainWrapper() +{ + this->Main(); + // Thread has been terminated. + // Unlock the isTerminated mutex. + m_isTerminatedMutexLock.unlock(); +} + +bool +Thread::ShouldTerminate() const +{ + boost::timed_mutex::scoped_try_lock lock(m_shouldTerminateMutex); + return lock.locked(); +} + diff --git a/src/core/thread.h b/src/core/thread.h new file mode 100644 index 00000000..c8127568 --- /dev/null +++ b/src/core/thread.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* Base class for threads (used by network client/server). */ + +#include +#include + +class Thread +{ +public: + Thread(); + virtual ~Thread(); + + // Start the thread. Will do nothing if the + // thread was already started. + void Run(); + + // Signal that the thread should be terminated + void SignalTermination(); + + // Wait for the termination of the thread. + // Only one Thread should wait for the termination! + // You SHOULD always call join for a thread. + bool Join(unsigned msecTimeout); + +protected: + + // Startup function. + void MainWrapper(); + + // Main function of the thread. + virtual void Main() = 0; + + // Checks whether termination has been requested. + bool ShouldTerminate() const; + +private: + + // Flag specifying whether the application code within the + // thread was terminated. + mutable boost::timed_mutex m_isTerminatedMutex; + mutable boost::timed_mutex::scoped_try_lock m_isTerminatedMutexLock; + + // Flag specifying whether the thread should be terminated. + mutable boost::timed_mutex m_shouldTerminateMutex; + mutable boost::timed_mutex::scoped_try_lock m_userReqTerminateLock; + + // The boost thread object. + boost::shared_ptr m_threadObj; + mutable boost::mutex m_threadObjMutex; + +friend class ThreadStarter; +}; + diff --git a/src/net/win32/socket_helper.cpp b/src/net/win32/socket_helper.cpp index 2a3c831d..85943621 100644 --- a/src/net/win32/socket_helper.cpp +++ b/src/net/win32/socket_helper.cpp @@ -86,7 +86,7 @@ socket_resolve(const char *str, const char *port, int addrFamily, int sockType, if (hWsock) { - // Determine functions at runtime, because some operating system do not + // Determine functions at runtime, because some windows systems do not // support the unicode version of getaddrinfo. getaddrinfow_ptr_t getaddrinfow_ptr = (getaddrinfow_ptr_t)::GetProcAddress(hWsock, "GetAddrInfoW"); freeaddrinfow_ptr_t freeaddrinfow_ptr = (freeaddrinfow_ptr_t)::GetProcAddress(hWsock, "FreeAddrInfoW"); @@ -106,6 +106,7 @@ socket_resolve(const char *str, const char *port, int addrFamily, int sockType, aiHints.ai_socktype = sockType; aiHints.ai_protocol = protocol; + // resolve the name (unicode). bool success = (getaddrinfow_ptr(wstr.c_str(), wport.c_str(), &aiHints, &aiList) == 0); if (success && aiList)