diff options
author | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-24 19:08:15 +0000 |
---|---|---|
committer | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-24 19:08:15 +0000 |
commit | d256e6b2991b8d2ba0a613242d545856540f9540 (patch) | |
tree | 771389eae254ef226932184cd3bfb7dfd75c0cb5 | |
parent | edd3b0a50912b04fe9d7e5dbf6f9639144cc09e4 (diff) | |
download | chromium_src-d256e6b2991b8d2ba0a613242d545856540f9540.zip chromium_src-d256e6b2991b8d2ba0a613242d545856540f9540.tar.gz chromium_src-d256e6b2991b8d2ba0a613242d545856540f9540.tar.bz2 |
Update Signal Thread to use ref counting and locks to ensure thread safety.
Review URL: http://codereview.chromium.org/418042
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32948 0039d316-1c4b-4281-b951-d872f2087c98
12 files changed, 590 insertions, 78 deletions
diff --git a/chrome/browser/sync/notifier/base/signal_thread_task.h b/chrome/browser/sync/notifier/base/signal_thread_task.h index ebee005..82853a3 100644 --- a/chrome/browser/sync/notifier/base/signal_thread_task.h +++ b/chrome/browser/sync/notifier/base/signal_thread_task.h @@ -77,7 +77,8 @@ class SignalThreadTask : public talk_base::Task, void ClearSignalThread() { if (signal_thread_) { - signal_thread_->Destroy(); + // Don't wait on the thread destruction, or we may deadlock. + signal_thread_->Destroy(false); signal_thread_ = NULL; } } diff --git a/chrome/browser/sync/notifier/listener/mediator_thread_impl.cc b/chrome/browser/sync/notifier/listener/mediator_thread_impl.cc index 62d44c0..d688b7e 100644 --- a/chrome/browser/sync/notifier/listener/mediator_thread_impl.cc +++ b/chrome/browser/sync/notifier/listener/mediator_thread_impl.cc @@ -68,7 +68,7 @@ void MediatorThreadImpl::Run() { pump_->WakeTasks(); } MessageLoop::current()->RunAllPending(); - } while (!IsStopping()); + } while (!IsQuitting()); #if defined(OS_WIN) set_socketserver(old_socket_server); diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium index 3259d69..a4d124e 100644 --- a/third_party/libjingle/README.chromium +++ b/third_party/libjingle/README.chromium @@ -38,3 +38,5 @@ Local Modifications: * Added a #define guard to libjingle's base/logging.h to prevent the LOG() macros from being redefined when included by users of the library. The #define guard is SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS. + * Updated signalthread.* and dependencies to add threadcounting and + improve multithread safety. diff --git a/third_party/libjingle/files/talk/base/asynchttprequest.h b/third_party/libjingle/files/talk/base/asynchttprequest.h index 65bfa26..7f2f348 100644 --- a/third_party/libjingle/files/talk/base/asynchttprequest.h +++ b/third_party/libjingle/files/talk/base/asynchttprequest.h @@ -20,8 +20,7 @@ class FirewallManager; class MemoryStream; class AsyncHttpRequest: - public SignalThread, - public sigslot::has_slots<> { + public SignalThread { public: AsyncHttpRequest(const std::string &user_agent); diff --git a/third_party/libjingle/files/talk/base/autodetectproxy.cc b/third_party/libjingle/files/talk/base/autodetectproxy.cc index 917c548..cda405f 100644 --- a/third_party/libjingle/files/talk/base/autodetectproxy.cc +++ b/third_party/libjingle/files/talk/base/autodetectproxy.cc @@ -111,7 +111,7 @@ void AutoDetectProxy::Complete(talk_base::ProxyType type) { LOG_V(sev) << "AutoDetectProxy detected " << proxy_.address.ToString() << " as type " << proxy_.type; - Thread::Current()->MessageQueue::Stop(); + Thread::Current()->Quit(); } void AutoDetectProxy::OnConnectEvent(talk_base::AsyncSocket * socket) { diff --git a/third_party/libjingle/files/talk/base/autodetectproxy.h b/third_party/libjingle/files/talk/base/autodetectproxy.h index 9633d31..43d765e 100644 --- a/third_party/libjingle/files/talk/base/autodetectproxy.h +++ b/third_party/libjingle/files/talk/base/autodetectproxy.h @@ -19,7 +19,7 @@ namespace talk_base { class AsyncSocket; -class AutoDetectProxy : public SignalThread, public sigslot::has_slots<> { +class AutoDetectProxy : public SignalThread { public: AutoDetectProxy(const std::string& user_agent); diff --git a/third_party/libjingle/files/talk/base/messagequeue.cc b/third_party/libjingle/files/talk/base/messagequeue.cc index 48a372b..171f324 100644 --- a/third_party/libjingle/files/talk/base/messagequeue.cc +++ b/third_party/libjingle/files/talk/base/messagequeue.cc @@ -101,6 +101,10 @@ MessageQueue::MessageQueue(SocketServer* ss) } MessageQueue::~MessageQueue() { + // The signal is done from here to ensure + // that it always gets called when the queue + // is going away. + SignalQueueDestroyed(); if (active_) { MessageQueueManager::Instance()->Remove(this); Clear(NULL); @@ -111,12 +115,12 @@ void MessageQueue::set_socketserver(SocketServer* ss) { ss_ = ss; } -void MessageQueue::Stop() { +void MessageQueue::Quit() { fStop_ = true; ss_->WakeUp(); } -bool MessageQueue::IsStopping() { +bool MessageQueue::IsQuitting() { return fStop_; } diff --git a/third_party/libjingle/files/talk/base/messagequeue.h b/third_party/libjingle/files/talk/base/messagequeue.h index 5ef976d..d39aab8 100644 --- a/third_party/libjingle/files/talk/base/messagequeue.h +++ b/third_party/libjingle/files/talk/base/messagequeue.h @@ -160,9 +160,8 @@ public: // Get (or Peek) returns false. By guaranteeing delivery of those messages, // we eliminate the race condition when an MessageHandler and MessageQueue // may be destroyed independently of each other. - - virtual void Stop(); - virtual bool IsStopping(); + virtual void Quit(); + virtual bool IsQuitting(); virtual void Restart(); // Get() will process I/O until: @@ -187,6 +186,10 @@ public: } } + // When this signal is sent out, any references to this queue should + // no longer be used. + sigslot::signal0<> SignalQueueDestroyed; + protected: void EnsureActive(); diff --git a/third_party/libjingle/files/talk/base/signalthread.cc b/third_party/libjingle/files/talk/base/signalthread.cc index 0b5154d6..c9ac86a 100644 --- a/third_party/libjingle/files/talk/base/signalthread.cc +++ b/third_party/libjingle/files/talk/base/signalthread.cc @@ -10,22 +10,31 @@ using namespace talk_base; SignalThread::SignalThread() : main_(Thread::Current()), state_(kInit) { - worker_.SetParent(this); + main_->SignalQueueDestroyed.connect(this, + &SignalThread::OnMainThreadDestroyed); + refcount_ = 1; + worker_.parent_ = this; +} + +void SignalThread::OnMainThreadDestroyed() { + EnterExit ee(this); + main_ = NULL; } SignalThread::~SignalThread() { - worker_.SetParent(NULL); } void SignalThread::SetPriority(ThreadPriority priority) { + EnterExit ee(this); ASSERT(main_->IsCurrent()); ASSERT(kInit == state_); worker_.SetPriority(priority); } void SignalThread::Start() { + EnterExit ee(this); ASSERT(main_->IsCurrent()); - if (kInit == state_) { + if (kInit == state_ || kComplete == state_) { state_ = kRunning; OnWorkStart(); worker_.Start(); @@ -34,18 +43,24 @@ void SignalThread::Start() { } } -void SignalThread::Destroy() { +void SignalThread::Destroy(bool wait) { + EnterExit ee(this); ASSERT(main_->IsCurrent()); if ((kInit == state_) || (kComplete == state_)) { - delete this; - } else if (kRunning == state_) { + refcount_--; + } else if (kRunning == state_ || kReleasing == state_) { state_ = kStopping; - // A couple tricky issues here: - // 1) Thread::Stop() calls Join(), which we don't want... we just want - // to stop the MessageQueue, which causes ContinueWork() to return false. - // 2) OnWorkStop() must follow Stop(), so that when the thread wakes up - // due to OWS(), ContinueWork() will return false. - worker_.MessageQueue::Stop(); + // OnWorkStop() must follow Quit(), so that when the thread wakes up due to + // OWS(), ContinueWork() will return false. + if (wait) { + // Release the thread's lock so that it can return from ::Run. + cs_.Leave(); + worker_.Stop(); + cs_.Enter(); + refcount_--; + } else { + worker_.Quit(); + } OnWorkStop(); } else { ASSERT(false); @@ -53,9 +68,10 @@ void SignalThread::Destroy() { } void SignalThread::Release() { + EnterExit ee(this); ASSERT(main_->IsCurrent()); if (kComplete == state_) { - delete this; + refcount_--; } else if (kRunning == state_) { state_ = kReleasing; } else { @@ -65,11 +81,13 @@ void SignalThread::Release() { } bool SignalThread::ContinueWork() { + EnterExit ee(this); ASSERT(worker_.IsCurrent()); return worker_.ProcessMessages(0); } void SignalThread::OnMessage(Message *msg) { + EnterExit ee(this); if (ST_MSG_WORKER_DONE == msg->message_id) { ASSERT(main_->IsCurrent()); OnWorkDone(); @@ -80,15 +98,31 @@ void SignalThread::OnMessage(Message *msg) { do_delete = true; } if (kStopping != state_) { + // Before signaling that the work is done, make sure that the worker + // thread actually is done. We got here because DoWork() finished and + // Run() posted the ST_MSG_WORKER_DONE message. This means the worker + // thread is about to go away anyway, but sometimes it doesn't actually + // finish before SignalWorkDone is processed, and for a reusable + // SignalThread this makes an assert in thread.cc fire. + // + // Calling Stop() on the worker ensures that the OS thread that underlies + // the worker will finish, and will be set to NULL, enabling us to call + // Start() again. + worker_.Stop(); SignalWorkDone(this); } if (do_delete) { - delete this; + refcount_--; } } } void SignalThread::Run() { DoWork(); - main_->Post(this, ST_MSG_WORKER_DONE); + { + EnterExit ee(this); + if (main_) { + main_->Post(this, ST_MSG_WORKER_DONE); + } + } } diff --git a/third_party/libjingle/files/talk/base/signalthread.h b/third_party/libjingle/files/talk/base/signalthread.h index ccba912..ad6b46a 100644 --- a/third_party/libjingle/files/talk/base/signalthread.h +++ b/third_party/libjingle/files/talk/base/signalthread.h @@ -13,13 +13,17 @@ namespace talk_base { // Cancellation: Call Release(true), to abort the worker thread. // Fire-and-forget: Call Release(false), which allows the thread to run to // completion, and then self-destruct without further notification. +// Periodic tasks: Wait for SignalWorkDone, then eventually call Start() +// again to repeat the task. When the instance isn't needed anymore, +// call Release. DoWork, OnWorkStart and OnWorkStop are called again, +// on a new thread. // The subclass should override DoWork() to perform the background task. By // periodically calling ContinueWork(), it can check for cancellation. // OnWorkStart and OnWorkDone can be overridden to do pre- or post-work // tasks in the context of the main thread. /////////////////////////////////////////////////////////////////////////////// -class SignalThread : protected MessageHandler { +class SignalThread : public sigslot::has_slots<>, protected MessageHandler { public: SignalThread(); @@ -32,8 +36,9 @@ public: // Context: Main Thread. If the worker thread is not running, deletes the // object immediately. Otherwise, asks the worker thread to abort processing, // and schedules the object to be deleted once the worker exits. - // SignalWorkDone will not be signalled. - void Destroy(); + // SignalWorkDone will not be signalled. If wait is true, does not return + // until the thread is deleted. + void Destroy(bool wait); // Context: Main Thread. If the worker thread is complete, deletes the // object immediately. Otherwise, schedules the object to be deleted once @@ -50,11 +55,11 @@ protected: // Context: Main Thread. Subclass should override to do pre-work setup. virtual void OnWorkStart() { } - + // Context: Worker Thread. Subclass should override to do work. virtual void DoWork() = 0; - // Context: Worker Thread. Subclass should call periodically to + // Context: Worker Thread. Subclass should call periodically to // dispatch messages and determine if the thread should terminate. bool ContinueWork(); @@ -64,7 +69,7 @@ protected: // Context: Main Thread. Subclass should override to do post-work cleanup. virtual void OnWorkDone() { } - + // Context: Any Thread. If subclass overrides, be sure to call the base // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) virtual void OnMessage(Message *msg); @@ -73,26 +78,44 @@ private: friend class Worker; class Worker : public Thread { public: - virtual void Run() { - CritScope cs(&parent_crit_); - if (parent_) - parent_->Run(); + SignalThread* parent_; + virtual void Run() { parent_->Run(); } + }; + + class EnterExit { + friend class SignalThread; + + SignalThread * t_; + + EnterExit(SignalThread * t) : t_(t) { + t_->cs_.Enter(); + t_->refcount_ += 1; } - void SetParent(SignalThread* parent) { - CritScope cs(&parent_crit_); - parent_ = parent; + ~EnterExit() { + bool d = (0 == (--(t_->refcount_))); + t_->cs_.Leave(); + if (d) + delete t_; } - - private: - SignalThread* parent_; - CriticalSection parent_crit_; }; + friend class EnterExit; + + CriticalSection cs_; + int refcount_; + void Run(); + void OnMainThreadDestroyed(); Thread* main_; Worker worker_; - enum State { kInit, kRunning, kComplete, kStopping, kReleasing } state_; + enum State { + kInit, // Initialized, but not started + kRunning, // Started and doing work + kReleasing, // Same as running, but to be deleted when work is done + kComplete, // Work is done + kStopping, // Work is being interrupted + } state_; }; /////////////////////////////////////////////////////////////////////////////// diff --git a/third_party/libjingle/files/talk/base/thread.cc b/third_party/libjingle/files/talk/base/thread.cc index 99fa701..fa2d23c 100644 --- a/third_party/libjingle/files/talk/base/thread.cc +++ b/third_party/libjingle/files/talk/base/thread.cc @@ -131,8 +131,8 @@ void Thread::Start() { // Make sure Join() hasn't been called yet. if (stopped_) return; - pthread_create(&thread_, &attr, PreRun, this); - started_ = true; + if (pthread_create(&thread_, &attr, PreRun, this) == 0) + started_ = true; } void Thread::Join() { @@ -141,6 +141,7 @@ void Thread::Join() { if (started_) { void *pv; pthread_join(thread_, &pv); + started_ = false; } } #endif @@ -225,7 +226,7 @@ void Thread::Run() { } void Thread::Stop() { - MessageQueue::Stop(); + MessageQueue::Quit(); Join(); } @@ -347,7 +348,7 @@ bool Thread::ProcessMessages(int cmsLoop) { while (true) { Message msg; if (!Get(&msg, cmsNext)) - return false; + return !IsQuitting(); Dispatch(&msg); if (cmsLoop != kForever) { diff --git a/third_party/libjingle/mods-since-v0_4_0.diff b/third_party/libjingle/mods-since-v0_4_0.diff index 6c63ac6..b36cf65 100644 --- a/third_party/libjingle/mods-since-v0_4_0.diff +++ b/third_party/libjingle/mods-since-v0_4_0.diff @@ -1,5 +1,5 @@ -Only in libjingle/files/: .svn -Only in libjingle-0.4.0/: Makefile.in +Only in libjingle/files: .svn +Only in libjingle-0.4.0: Makefile.in diff -r libjingle-0.4.0/README libjingle/files/README 1,39c1,39 < Libjingle
@@ -168,8 +168,8 @@ diff -r libjingle-0.4.0/README.win libjingle/files/README.win > > 9. Build the solution > -Only in libjingle-0.4.0/: aclocal.m4 -Only in libjingle-0.4.0/: config.guess +Only in libjingle-0.4.0: aclocal.m4 +Only in libjingle-0.4.0: config.guess diff -r libjingle-0.4.0/config.h libjingle/files/config.h 14c14 < #define HAVE_ALSA_ASOUNDLIB_H 1 @@ -199,17 +199,41 @@ diff -r libjingle-0.4.0/config.h libjingle/files/config.h < #define __ALSA_ENABLED__ 1 --- > /* #undef __ALSA_ENABLED__ */ -Only in libjingle-0.4.0/: config.h.in -Only in libjingle-0.4.0/: config.sub -Only in libjingle-0.4.0/: configure -Only in libjingle-0.4.0/: depcomp -Only in libjingle-0.4.0/: install-sh -Only in libjingle-0.4.0/: ltmain.sh -Only in libjingle-0.4.0/: missing +Only in libjingle-0.4.0: config.h.in +Only in libjingle-0.4.0: config.sub +Only in libjingle-0.4.0: configure +Only in libjingle-0.4.0: depcomp +Only in libjingle-0.4.0: install-sh +Only in libjingle-0.4.0: ltmain.sh +Only in libjingle-0.4.0: missing Only in libjingle/files/talk: .svn Only in libjingle-0.4.0/talk: Makefile.in Only in libjingle/files/talk/base: .svn Only in libjingle-0.4.0/talk/base: Makefile.in +diff -r libjingle-0.4.0/talk/base/asynchttprequest.h libjingle/files/talk/base/asynchttprequest.h +23,24c23 +< public SignalThread, +< public sigslot::has_slots<> { +--- +> public SignalThread { +diff -r libjingle-0.4.0/talk/base/asynctcpsocket.cc libjingle/files/talk/base/asynctcpsocket.cc +31a32,33 +> #include <cstring> +> +diff -r libjingle-0.4.0/talk/base/autodetectproxy.cc libjingle/files/talk/base/autodetectproxy.cc +29c29 +< #include "talk/base/httpcommon.h" +--- +> #include "talk/base/httpcommon-inl.h" +114c114 +< Thread::Current()->MessageQueue::Stop(); +--- +> Thread::Current()->Quit(); +diff -r libjingle-0.4.0/talk/base/autodetectproxy.h libjingle/files/talk/base/autodetectproxy.h +22c22 +< class AutoDetectProxy : public SignalThread, public sigslot::has_slots<> { +--- +> class AutoDetectProxy : public SignalThread { diff -r libjingle-0.4.0/talk/base/base64.h libjingle/files/talk/base/base64.h 26,27c26,27 < static const std::string Base64::Base64Table; @@ -229,6 +253,36 @@ diff -r libjingle-0.4.0/talk/base/common.h libjingle/files/talk/base/common.h < TypeName(const TypeName&); \ < void operator=(const TypeName&) < +diff -r libjingle-0.4.0/talk/base/criticalsection.h libjingle/files/talk/base/criticalsection.h +83c83 +< public: +--- +> public: +85a86 +> pthread_mutexattr_init(&mutex_attribute); +87a89,90 +> pthread_mutexattr_destroy(&mutex_attribute); +> TRACK_OWNER(thread_ = 0); +93a97 +> TRACK_OWNER(thread_ = pthread_self()); +95a100 +> TRACK_OWNER(thread_ = 0); +98c103,110 +< private: +--- +> +> #if CS_TRACK_OWNER +> bool CurrentThreadIsOwner() const { +> return pthread_equal(thread_, pthread_self()); +> } +> #endif // CS_TRACK_OWNER +> +> private: +99a112 +> TRACK_OWNER(pthread_t thread_); +diff -r libjingle-0.4.0/talk/base/cryptstring.h libjingle/files/talk/base/cryptstring.h +30a31 +> #include <string.h> diff -r libjingle-0.4.0/talk/base/diskcache_win32.cc libjingle/files/talk/base/diskcache_win32.cc 38c38 < entry->streams = max(entry->streams, index + 1); @@ -237,6 +291,9 @@ diff -r libjingle-0.4.0/talk/base/diskcache_win32.cc libjingle/files/talk/base/d diff -r libjingle-0.4.0/talk/base/helpers.cc libjingle/files/talk/base/helpers.cc 38a39 > #include <wincrypt.h> +diff -r libjingle-0.4.0/talk/base/host.cc libjingle/files/talk/base/host.cc +30a31 +> #include <cstdlib> diff -r libjingle-0.4.0/talk/base/httpclient.cc libjingle/files/talk/base/httpclient.cc 670a671 > HttpAuthContext *context = context_.get(); @@ -245,6 +302,19 @@ diff -r libjingle-0.4.0/talk/base/httpclient.cc libjingle/files/talk/base/httpcl --- > context, response, auth_method); > context_.reset(context); +diff -r libjingle-0.4.0/talk/base/logging.cc libjingle/files/talk/base/logging.cc +27a28 +> #include <stdio.h> +diff -r libjingle-0.4.0/talk/base/logging.h libjingle/files/talk/base/logging.h +67a68,69 +> +> #if defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS) +70a73 +> #endif // defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS) +195a199 +> #if defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS) +290a295 +> #endif // defined(SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS) diff -r libjingle-0.4.0/talk/base/messagequeue.cc libjingle/files/talk/base/messagequeue.cc 98,99c98,99 < new_ss = true; @@ -252,19 +322,78 @@ diff -r libjingle-0.4.0/talk/base/messagequeue.cc libjingle/files/talk/base/mess --- > default_ss_.reset(new PhysicalSocketServer()); > ss_ = default_ss_.get(); -108,109d107 +103a104,107 +> // The signal is done from here to ensure +> // that it always gets called when the queue +> // is going away. +> SignalQueueDestroyed(); +108,109d111 < if (new_ss) < delete ss_; -113,115d110 +113,115d114 < if (new_ss) < delete ss_; < new_ss = false; +119c118 +< void MessageQueue::Stop() { +--- +> void MessageQueue::Quit() { +124c123 +< bool MessageQueue::IsStopping() { +--- +> bool MessageQueue::IsQuitting() { diff -r libjingle-0.4.0/talk/base/messagequeue.h libjingle/files/talk/base/messagequeue.h 35a36 > #include "talk/base/scoped_ptr.h" -192a194,195 +162,164c163,164 +< +< virtual void Stop(); +< virtual bool IsStopping(); +--- +> virtual void Quit(); +> virtual bool IsQuitting(); +188a189,192 +> // When this signal is sent out, any references to this queue should +> // no longer be used. +> sigslot::signal0<> SignalQueueDestroyed; +> +192a197,198 > // If a server isn't supplied in the constructor, use this one. > scoped_ptr<SocketServer> default_ss_; +diff -r libjingle-0.4.0/talk/base/natserver.cc libjingle/files/talk/base/natserver.cc +28a29 +> #include <cstring> +diff -r libjingle-0.4.0/talk/base/natsocketfactory.cc libjingle/files/talk/base/natsocketfactory.cc +29a30 +> #include <cstring> +diff -r libjingle-0.4.0/talk/base/physicalsocketserver.cc libjingle/files/talk/base/physicalsocketserver.cc +61a62 +> #include "talk/base/winsock_initializer.h" +67,86d67 +< #ifdef WIN32 +< class WinsockInitializer { +< public: +< WinsockInitializer() { +< WSADATA wsaData; +< WORD wVersionRequested = MAKEWORD(1, 0); +< err_ = WSAStartup(wVersionRequested, &wsaData); +< } +< ~WinsockInitializer() { +< WSACleanup(); +< } +< int error() { +< return err_; +< } +< private: +< int err_; +< }; +< WinsockInitializer g_winsockinit; +< #endif +< +124a106,108 +> #ifdef WIN32 +> EnsureWinsockInit(); +> #endif diff -r libjingle-0.4.0/talk/base/proxydetect.cc libjingle/files/talk/base/proxydetect.cc 205,206c205,206 < const char* list = slist.c_str(); @@ -525,15 +654,188 @@ diff -r libjingle-0.4.0/talk/base/scoped_ptr.h libjingle/files/talk/base/scoped_ < using talk_base::scoped_ptr; --- > #include "base/scoped_ptr.h" +diff -r libjingle-0.4.0/talk/base/signalthread.cc libjingle/files/talk/base/signalthread.cc +12a13,15 +> main_->SignalQueueDestroyed.connect(this, +> &SignalThread::OnMainThreadDestroyed); +> refcount_ = 1; +15a19,23 +> void SignalThread::OnMainThreadDestroyed() { +> EnterExit ee(this); +> main_ = NULL; +> } +> +19a28 +> EnterExit ee(this); +25a35 +> EnterExit ee(this); +27c37 +< if (kInit == state_) { +--- +> if (kInit == state_ || kComplete == state_) { +36c46,47 +< void SignalThread::Destroy() { +--- +> void SignalThread::Destroy(bool wait) { +> EnterExit ee(this); +39,40c50,51 +< delete this; +< } else if (kRunning == state_) { +--- +> refcount_--; +> } else if (kRunning == state_ || kReleasing == state_) { +42,47c53,63 +< // A couple tricky issues here: +< // 1) Thread::Stop() calls Join(), which we don't want... we just want +< // to stop the MessageQueue, which causes ContinueWork() to return false. +< // 2) OnWorkStop() must follow Stop(), so that when the thread wakes up +< // due to OWS(), ContinueWork() will return false. +< worker_.MessageQueue::Stop(); +--- +> // OnWorkStop() must follow Quit(), so that when the thread wakes up due to +> // OWS(), ContinueWork() will return false. +> if (wait) { +> // Release the thread's lock so that it can return from ::Run. +> cs_.Leave(); +> worker_.Stop(); +> cs_.Enter(); +> refcount_--; +> } else { +> worker_.Quit(); +> } +54a71 +> EnterExit ee(this); +57c74 +< delete this; +--- +> refcount_--; +66a84 +> EnterExit ee(this); +71a90 +> EnterExit ee(this); +81a101,111 +> // Before signaling that the work is done, make sure that the worker +> // thread actually is done. We got here because DoWork() finished and +> // Run() posted the ST_MSG_WORKER_DONE message. This means the worker +> // thread is about to go away anyway, but sometimes it doesn't actually +> // finish before SignalWorkDone is processed, and for a reusable +> // SignalThread this makes an assert in thread.cc fire. +> // +> // Calling Stop() on the worker ensures that the OS thread that underlies +> // the worker will finish, and will be set to NULL, enabling us to call +> // Start() again. +> worker_.Stop(); +85c115 +< delete this; +--- +> refcount_--; +92c122,127 +< main_->Post(this, ST_MSG_WORKER_DONE); +--- +> { +> EnterExit ee(this); +> if (main_) { +> main_->Post(this, ST_MSG_WORKER_DONE); +> } +> } +diff -r libjingle-0.4.0/talk/base/signalthread.h libjingle/files/talk/base/signalthread.h +15a16,19 +> // Periodic tasks: Wait for SignalWorkDone, then eventually call Start() +> // again to repeat the task. When the instance isn't needed anymore, +> // call Release. DoWork, OnWorkStart and OnWorkStop are called again, +> // on a new thread. +22c26 +< class SignalThread : protected MessageHandler { +--- +> class SignalThread : public sigslot::has_slots<>, protected MessageHandler { +35,36c39,41 +< // SignalWorkDone will not be signalled. +< void Destroy(); +--- +> // SignalWorkDone will not be signalled. If wait is true, does not return +> // until the thread is deleted. +> void Destroy(bool wait); +53c58 +< +--- +> +57c62 +< // Context: Worker Thread. Subclass should call periodically to +--- +> // Context: Worker Thread. Subclass should call periodically to +67c72 +< +--- +> +79a85,106 +> class EnterExit { +> friend class SignalThread; +> +> SignalThread * t_; +> +> EnterExit(SignalThread * t) : t_(t) { +> t_->cs_.Enter(); +> t_->refcount_ += 1; +> } +> ~EnterExit() { +> bool d = (0 == (--(t_->refcount_))); +> t_->cs_.Leave(); +> if (d) +> delete t_; +> } +> }; +> +> friend class EnterExit; +> +> CriticalSection cs_; +> int refcount_; +> +80a108 +> void OnMainThreadDestroyed(); +84c112,118 +< enum State { kInit, kRunning, kComplete, kStopping, kReleasing } state_; +--- +> enum State { +> kInit, // Initialized, but not started +> kRunning, // Started and doing work +> kReleasing, // Same as running, but to be deleted when work is done +> kComplete, // Work is done +> kStopping, // Work is being interrupted +> } state_; +Only in libjingle/files/talk/base: signalthread_unittest.cc diff -r libjingle-0.4.0/talk/base/socket.h libjingle/files/talk/base/socket.h 77a78 > #undef ETIMEDOUT // remove pthread.h's definition +diff -r libjingle-0.4.0/talk/base/socketadapters.cc libjingle/files/talk/base/socketadapters.cc +43a44,45 +> #include <cstring> +> +diff -r libjingle-0.4.0/talk/base/ssladapter.cc libjingle/files/talk/base/ssladapter.cc +34c34,35 +< #define SSL_USE_OPENSSL 1 +--- +> // Turn off OpenSSL +> //#define SSL_USE_OPENSSL 1 +84a86 +> #if SSL_USE_OPENSSL || SSL_USE_SCHANNEL +85a88,90 +> #else +> return NULL; +> #endif +diff -r libjingle-0.4.0/talk/base/stream.cc libjingle/files/talk/base/stream.cc +27a28 +> #include <stdio.h> +diff -r libjingle-0.4.0/talk/base/stringencode.cc libjingle/files/talk/base/stringencode.cc +34a35 +> #include <stdlib.h> diff -r libjingle-0.4.0/talk/base/stringutils.h libjingle/files/talk/base/stringutils.h -87a88 +33a34 +> #include <string.h> +87a89 > #if 0 -93a95 +93a96 > #endif -272c274 +272c275 < inline static const char* Traits<char>::empty_str() { return ""; } --- > inline static const char* empty_str() { return ""; } @@ -572,6 +874,74 @@ diff -r libjingle-0.4.0/talk/base/task.cc libjingle/files/talk/base/task.cc < Wake(); // to self-delete --- > GetRunner()->WakeTasks(); +diff -r libjingle-0.4.0/talk/base/taskrunner.h libjingle/files/talk/base/taskrunner.h +63a64,68 +> bool HasPendingTimeoutTask() { +> return next_timeout_task_ != NULL && +> next_timeout_task_->TimedOut(); +> } +> +diff -r libjingle-0.4.0/talk/base/testclient.cc libjingle/files/talk/base/testclient.cc +29a30 +> #include <cstring> +diff -r libjingle-0.4.0/talk/base/thread.cc libjingle/files/talk/base/thread.cc +100a101,105 +> bool ThreadManager::ThreadActive(Thread *thread) { +> CritScope cs(&crit_); +> return(std::find(threads_.begin(), threads_.end(), thread) != threads_.end()); +> } +> +103a109 +> stopped_ = false; +124,125c130,135 +< pthread_create(&thread_, &attr, PreRun, this); +< started_ = true; +--- +> CritScope cs(&started_crit_); +> // Make sure Join() hasn't been called yet. +> if (stopped_) +> return; +> if (pthread_create(&thread_, &attr, PreRun, this) == 0) +> started_ = true; +128a139,140 +> CritScope cs(&started_crit_); +> stopped_ = true; +168a181,184 +> CritScope cs(&started_crit_); +> // Make sure Join() hasn't been called yet. +> if (stopped_) +> return; +181a198,199 +> CritScope cs(&started_crit_); +> stopped_ = true; +191a210,212 +> // Make sure the thread hasn't been deleted. +> if (!g_thmgr.ThreadActive(thread)) +> return NULL; +207c228 +< MessageQueue::Stop(); +--- +> MessageQueue::Quit(); +329c350 +< return false; +--- +> return !IsQuitting(); +diff -r libjingle-0.4.0/talk/base/thread.h libjingle/files/talk/base/thread.h +57a58 +> bool ThreadActive(Thread *thread); +134a136 +> CriticalSection started_crit_; +135a138 +> bool stopped_; +diff -r libjingle-0.4.0/talk/base/urlencode.cc libjingle/files/talk/base/urlencode.cc +0a1,2 +> #include <stdlib.h> +> #include <string.h> +diff -r libjingle-0.4.0/talk/base/win32socketserver.cc libjingle/files/talk/base/win32socketserver.cc +31a32 +> #include "talk/base/winsock_initializer.h" +269a271 +> talk_base::EnsureWinsockInit(); diff -r libjingle-0.4.0/talk/base/winping.cc libjingle/files/talk/base/winping.cc 133c133 < return sizeof(ICMP_ECHO_REPLY) + max(8UL, data_size); @@ -582,6 +952,8 @@ diff -r libjingle-0.4.0/talk/base/winping.cc libjingle/files/talk/base/winping.c \ No newline at end of file --- > } // namespace talk_base +Only in libjingle/files/talk/base: winsock_initializer.cc +Only in libjingle/files/talk/base: winsock_initializer.h Only in libjingle-0.4.0/talk: examples Only in libjingle-0.4.0/talk: libjingle.sln Only in libjingle-0.4.0/talk: libjingle.vcproj @@ -589,16 +961,54 @@ Only in libjingle/files/talk/p2p: .svn Only in libjingle-0.4.0/talk/p2p: Makefile.in Only in libjingle/files/talk/p2p/base: .svn Only in libjingle-0.4.0/talk/p2p/base: Makefile.in +diff -r libjingle-0.4.0/talk/p2p/base/p2ptransport.cc libjingle/files/talk/p2p/base/p2ptransport.cc +37c37 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" diff -r libjingle-0.4.0/talk/p2p/base/port.cc libjingle/files/talk/p2p/base/port.cc -270c270 +34a35 +> #include <cstring> +270c271 < talk_base::scoped_ptr<StunMessage> stun_msg(new StunMessage()); --- > scoped_ptr<StunMessage> stun_msg(new StunMessage()); +diff -r libjingle-0.4.0/talk/p2p/base/rawtransport.cc libjingle/files/talk/p2p/base/rawtransport.cc +35c35 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" +diff -r libjingle-0.4.0/talk/p2p/base/rawtransportchannel.cc libjingle/files/talk/p2p/base/rawtransportchannel.cc +39c39 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" +diff -r libjingle-0.4.0/talk/p2p/base/relayport.cc libjingle/files/talk/p2p/base/relayport.cc +36a37 +> #include <cstring> +diff -r libjingle-0.4.0/talk/p2p/base/session.cc libjingle/files/talk/p2p/base/session.cc +32c32 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" +diff -r libjingle-0.4.0/talk/p2p/base/sessionmanager.cc libjingle/files/talk/p2p/base/sessionmanager.cc +32c32 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" diff -r libjingle-0.4.0/talk/p2p/base/sessionmanager.h libjingle/files/talk/p2p/base/sessionmanager.h 159c159 < buzz::XmlElement* SessionManager::CreateErrorMessage( --- > buzz::XmlElement* CreateErrorMessage( +diff -r libjingle-0.4.0/talk/p2p/base/stun.cc libjingle/files/talk/p2p/base/stun.cc +31a32 +> #include <cstring> +diff -r libjingle-0.4.0/talk/p2p/base/transport.cc libjingle/files/talk/p2p/base/transport.cc +34c34 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" Only in libjingle/files/talk/p2p/client: .svn Only in libjingle-0.4.0/talk/p2p/client: Makefile.in diff -r libjingle-0.4.0/talk/p2p/client/httpportallocator.cc libjingle/files/talk/p2p/client/httpportallocator.cc @@ -762,19 +1172,18 @@ diff -r libjingle-0.4.0/talk/xmllite/xmlprinter.cc libjingle/files/talk/xmllite/ > } Only in libjingle/files/talk/xmpp: .svn Only in libjingle-0.4.0/talk/xmpp: Makefile.in -diff -r libjingle-0.4.0/talk/xmpp/constants.cc libjingle/files/talk/xmpp/constants.cc -206a207,209 -> const std::string NS_GOOGLE_AUTH_PROTOCOL("http://www.google.com/talk/protocol/auth"); -> const QName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT(true, NS_GOOGLE_AUTH_PROTOCOL, "client-uses-full-bind-result"); -> -208a212 -> const QName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN(true, NS_GOOGLE_AUTH_PROTOCOL, "allow-non-google-login"); -diff -r libjingle-0.4.0/talk/xmpp/constants.h libjingle/files/talk/xmpp/constants.h -175a176,178 -> extern const std::string NS_GOOGLE_AUTH_PROTOCOL; -> extern const QName QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT; -> extern const QName QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN; +Only in libjingle-0.4.0/talk/xmpp: constants.cc +Only in libjingle-0.4.0/talk/xmpp: constants.h +diff -r libjingle-0.4.0/talk/xmpp/jid.cc libjingle/files/talk/xmpp/jid.cc +33c33 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" diff -r libjingle-0.4.0/talk/xmpp/saslcookiemechanism.h libjingle/files/talk/xmpp/saslcookiemechanism.h +33c33 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" 40,41c40,55 < SaslCookieMechanism(const std::string & mechanism, const std::string & username, const std::string & cookie) : < mechanism_(mechanism), username_(username), cookie_(cookie) {} @@ -806,6 +1215,16 @@ diff -r libjingle-0.4.0/talk/xmpp/saslcookiemechanism.h libjingle/files/talk/xmp diff -r libjingle-0.4.0/talk/xmpp/saslhandler.h libjingle/files/talk/xmpp/saslhandler.h 31a32 > #include <vector> +diff -r libjingle-0.4.0/talk/xmpp/saslmechanism.cc libjingle/files/talk/xmpp/saslmechanism.cc +30c30 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" +diff -r libjingle-0.4.0/talk/xmpp/xmppclient.cc libjingle/files/talk/xmpp/xmppclient.cc +30c30 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" diff -r libjingle-0.4.0/talk/xmpp/xmppclient.h libjingle/files/talk/xmpp/xmppclient.h 141c141 < std::string XmppClient::GetStateName(int state) const { @@ -820,8 +1239,34 @@ diff -r libjingle-0.4.0/talk/xmpp/xmppclientsettings.h libjingle/files/talk/xmpp > const std::string & token_service() const { return token_service_; } 93a98 > std::string token_service_; +Only in libjingle/files/talk/xmpp: xmppconstants.cc +Only in libjingle/files/talk/xmpp: xmppconstants.h +diff -r libjingle-0.4.0/talk/xmpp/xmppengineimpl.cc libjingle/files/talk/xmpp/xmppengineimpl.cc +37c37 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" +diff -r libjingle-0.4.0/talk/xmpp/xmppengineimpl_iq.cc libjingle/files/talk/xmpp/xmppengineimpl_iq.cc +32c32 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" diff -r libjingle-0.4.0/talk/xmpp/xmpplogintask.cc libjingle/files/talk/xmpp/xmpplogintask.cc +34c34 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" 218a219,221 > auth->SetAttr(QN_GOOGLE_ALLOW_NON_GOOGLE_ID_XMPP_LOGIN, "true"); > auth->SetAttr(QN_GOOGLE_AUTH_CLIENT_USES_FULL_BIND_RESULT, "true"); > +diff -r libjingle-0.4.0/talk/xmpp/xmppstanzaparser.cc libjingle/files/talk/xmpp/xmppstanzaparser.cc +32c32 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" +diff -r libjingle-0.4.0/talk/xmpp/xmpptask.cc libjingle/files/talk/xmpp/xmpptask.cc +31c31 +< #include "talk/xmpp/constants.h" +--- +> #include "talk/xmpp/xmppconstants.h" |