~ubuntu-branches/debian/experimental/kopete/experimental

« back to all changes in this revision

Viewing changes to protocols/jabber/libjingle/talk/base/signalthread.cc

  • Committer: Package Import Robot
  • Author(s): Maximiliano Curia
  • Date: 2015-02-24 11:32:57 UTC
  • mfrom: (1.1.41 vivid)
  • Revision ID: package-import@ubuntu.com-20150224113257-gnupg4v7lzz18ij0
Tags: 4:14.12.2-1
* New upstream release (14.12.2).
* Bump Standards-Version to 3.9.6, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * libjingle
 
3
 * Copyright 2004--2009, Google Inc.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions are met:
 
7
 *
 
8
 *  1. Redistributions of source code must retain the above copyright notice,
 
9
 *     this list of conditions and the following disclaimer.
 
10
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 
11
 *     this list of conditions and the following disclaimer in the documentation
 
12
 *     and/or other materials provided with the distribution.
 
13
 *  3. The name of the author may not be used to endorse or promote products
 
14
 *     derived from this software without specific prior written permission.
 
15
 *
 
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
17
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
18
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
19
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
20
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
21
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
22
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
23
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
24
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
25
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
26
 */
 
27
 
 
28
#include "talk/base/signalthread.h"
 
29
 
 
30
#include "talk/base/common.h"
 
31
 
 
32
namespace talk_base {
 
33
 
 
34
///////////////////////////////////////////////////////////////////////////////
 
35
// SignalThread
 
36
///////////////////////////////////////////////////////////////////////////////
 
37
 
 
38
SignalThread::SignalThread()
 
39
    : main_(Thread::Current()),
 
40
      worker_(this),
 
41
      state_(kInit),
 
42
      refcount_(1) {
 
43
  main_->SignalQueueDestroyed.connect(this,
 
44
                                      &SignalThread::OnMainThreadDestroyed);
 
45
  worker_.SetName("SignalThread", this);
 
46
}
 
47
 
 
48
SignalThread::~SignalThread() {
 
49
  ASSERT(refcount_ == 0);
 
50
}
 
51
 
 
52
bool SignalThread::SetName(const std::string& name, const void* obj) {
 
53
  EnterExit ee(this);
 
54
  ASSERT(main_->IsCurrent());
 
55
  ASSERT(kInit == state_);
 
56
  return worker_.SetName(name, obj);
 
57
}
 
58
 
 
59
bool SignalThread::SetPriority(ThreadPriority priority) {
 
60
  EnterExit ee(this);
 
61
  ASSERT(main_->IsCurrent());
 
62
  ASSERT(kInit == state_);
 
63
  return worker_.SetPriority(priority);
 
64
}
 
65
 
 
66
void SignalThread::Start() {
 
67
  EnterExit ee(this);
 
68
  ASSERT(main_->IsCurrent());
 
69
  if (kInit == state_ || kComplete == state_) {
 
70
    state_ = kRunning;
 
71
    OnWorkStart();
 
72
    worker_.Start();
 
73
  } else {
 
74
    ASSERT(false);
 
75
  }
 
76
}
 
77
 
 
78
void SignalThread::Destroy(bool wait) {
 
79
  EnterExit ee(this);
 
80
  ASSERT(main_->IsCurrent());
 
81
  if ((kInit == state_) || (kComplete == state_)) {
 
82
    refcount_--;
 
83
  } else if (kRunning == state_ || kReleasing == state_) {
 
84
    state_ = kStopping;
 
85
    // OnWorkStop() must follow Quit(), so that when the thread wakes up due to
 
86
    // OWS(), ContinueWork() will return false.
 
87
    worker_.Quit();
 
88
    OnWorkStop();
 
89
    if (wait) {
 
90
      // Release the thread's lock so that it can return from ::Run.
 
91
      cs_.Leave();
 
92
      worker_.Stop();
 
93
      cs_.Enter();
 
94
      refcount_--;
 
95
    }
 
96
  } else {
 
97
    ASSERT(false);
 
98
  }
 
99
}
 
100
 
 
101
void SignalThread::Release() {
 
102
  EnterExit ee(this);
 
103
  ASSERT(main_->IsCurrent());
 
104
  if (kComplete == state_) {
 
105
    refcount_--;
 
106
  } else if (kRunning == state_) {
 
107
    state_ = kReleasing;
 
108
  } else {
 
109
    // if (kInit == state_) use Destroy()
 
110
    ASSERT(false);
 
111
  }
 
112
}
 
113
 
 
114
bool SignalThread::ContinueWork() {
 
115
  EnterExit ee(this);
 
116
  ASSERT(worker_.IsCurrent());
 
117
  return worker_.ProcessMessages(0);
 
118
}
 
119
 
 
120
void SignalThread::OnMessage(Message *msg) {
 
121
  EnterExit ee(this);
 
122
  if (ST_MSG_WORKER_DONE == msg->message_id) {
 
123
    ASSERT(main_->IsCurrent());
 
124
    OnWorkDone();
 
125
    bool do_delete = false;
 
126
    if (kRunning == state_) {
 
127
      state_ = kComplete;
 
128
    } else {
 
129
      do_delete = true;
 
130
    }
 
131
    if (kStopping != state_) {
 
132
      // Before signaling that the work is done, make sure that the worker
 
133
      // thread actually is done. We got here because DoWork() finished and
 
134
      // Run() posted the ST_MSG_WORKER_DONE message. This means the worker
 
135
      // thread is about to go away anyway, but sometimes it doesn't actually
 
136
      // finish before SignalWorkDone is processed, and for a reusable
 
137
      // SignalThread this makes an assert in thread.cc fire.
 
138
      //
 
139
      // Calling Stop() on the worker ensures that the OS thread that underlies
 
140
      // the worker will finish, and will be set to NULL, enabling us to call
 
141
      // Start() again.
 
142
      worker_.Stop();
 
143
      SignalWorkDone(this);
 
144
    }
 
145
    if (do_delete) {
 
146
      refcount_--;
 
147
    }
 
148
  }
 
149
}
 
150
 
 
151
void SignalThread::Run() {
 
152
  DoWork();
 
153
  {
 
154
    EnterExit ee(this);
 
155
    if (main_) {
 
156
      main_->Post(this, ST_MSG_WORKER_DONE);
 
157
    }
 
158
  }
 
159
}
 
160
 
 
161
void SignalThread::OnMainThreadDestroyed() {
 
162
  EnterExit ee(this);
 
163
  main_ = NULL;
 
164
}
 
165
 
 
166
}  // namespace talk_base