/src/mozilla-central/media/mtransport/nr_timer.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
8 | | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
9 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
10 | | |
11 | | // Original code by: ekr@rtfm.com |
12 | | |
13 | | // Implementation of the NR timer interface |
14 | | |
15 | | // Some code here copied from nrappkit. The license was. |
16 | | |
17 | | /** |
18 | | Copyright (C) 2004, Network Resonance, Inc. |
19 | | Copyright (C) 2006, Network Resonance, Inc. |
20 | | All Rights Reserved |
21 | | |
22 | | Redistribution and use in source and binary forms, with or without |
23 | | modification, are permitted provided that the following conditions |
24 | | are met: |
25 | | |
26 | | 1. Redistributions of source code must retain the above copyright |
27 | | notice, this list of conditions and the following disclaimer. |
28 | | 2. Redistributions in binary form must reproduce the above copyright |
29 | | notice, this list of conditions and the following disclaimer in the |
30 | | documentation and/or other materials provided with the distribution. |
31 | | 3. Neither the name of Network Resonance, Inc. nor the name of any |
32 | | contributors to this software may be used to endorse or promote |
33 | | products derived from this software without specific prior written |
34 | | permission. |
35 | | |
36 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' |
37 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
38 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
39 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
40 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
41 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
42 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
43 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
44 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
45 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
46 | | POSSIBILITY OF SUCH DAMAGE. |
47 | | |
48 | | |
49 | | ekr@rtfm.com Sun Feb 22 19:35:24 2004 |
50 | | */ |
51 | | |
52 | | #include <string> |
53 | | |
54 | | #include "nsCOMPtr.h" |
55 | | #include "nsComponentManagerUtils.h" |
56 | | #include "nsServiceManagerUtils.h" |
57 | | #include "nsIEventTarget.h" |
58 | | #include "nsINamed.h" |
59 | | #include "nsITimer.h" |
60 | | #include "nsNetCID.h" |
61 | | #include "runnable_utils.h" |
62 | | #include "mozilla/DebugOnly.h" |
63 | | |
64 | | extern "C" { |
65 | | #include "nr_api.h" |
66 | | #include "async_timer.h" |
67 | | } |
68 | | |
69 | | |
70 | | namespace mozilla { |
71 | | |
72 | | class nrappkitCallback { |
73 | | public: |
74 | | nrappkitCallback(NR_async_cb cb, void *cb_arg, |
75 | | const char *function, int line) |
76 | 0 | : cb_(cb), cb_arg_(cb_arg), function_(function), line_(line) { |
77 | 0 | } |
78 | 0 | virtual ~nrappkitCallback() {} |
79 | | |
80 | | virtual void Cancel() = 0; |
81 | | |
82 | | protected: |
83 | | /* additional members */ |
84 | | NR_async_cb cb_; |
85 | | void *cb_arg_; |
86 | | std::string function_; |
87 | | int line_; |
88 | | }; |
89 | | |
90 | | class nrappkitTimerCallback : public nrappkitCallback, |
91 | | public nsITimerCallback, |
92 | | public nsINamed { |
93 | | public: |
94 | | // We're going to release ourself in the callback, so we need to be threadsafe |
95 | | NS_DECL_THREADSAFE_ISUPPORTS |
96 | | NS_DECL_NSITIMERCALLBACK |
97 | | |
98 | | nrappkitTimerCallback(NR_async_cb cb, void *cb_arg, |
99 | | const char *function, int line) |
100 | | : nrappkitCallback(cb, cb_arg, function, line), |
101 | 0 | timer_(nullptr) {} |
102 | | |
103 | 0 | void SetTimer(already_AddRefed<nsITimer>&& timer) { |
104 | 0 | timer_ = timer; |
105 | 0 | } |
106 | | |
107 | 0 | virtual void Cancel() override { |
108 | 0 | AddRef(); // Cancelling the timer causes the callback it holds to |
109 | 0 | // be released. AddRef() keeps us alive. |
110 | 0 | timer_->Cancel(); |
111 | 0 | timer_ = nullptr; |
112 | 0 | Release(); // Will cause deletion of this object. |
113 | 0 | } |
114 | | |
115 | | NS_IMETHOD |
116 | 0 | GetName(nsACString& aName) override { |
117 | 0 | aName.AssignLiteral("nrappkitTimerCallback"); |
118 | 0 | return NS_OK; |
119 | 0 | } |
120 | | |
121 | | private: |
122 | | nsCOMPtr<nsITimer> timer_; |
123 | 0 | virtual ~nrappkitTimerCallback() {} |
124 | | }; |
125 | | |
126 | | NS_IMPL_ISUPPORTS(nrappkitTimerCallback, nsITimerCallback, nsINamed) |
127 | | |
128 | 0 | NS_IMETHODIMP nrappkitTimerCallback::Notify(nsITimer *timer) { |
129 | 0 | r_log(LOG_GENERIC, LOG_DEBUG, "Timer callback fired (set in %s:%d)", |
130 | 0 | function_.c_str(), line_); |
131 | 0 | MOZ_RELEASE_ASSERT(timer == timer_); |
132 | 0 | cb_(nullptr, 0, cb_arg_); |
133 | 0 |
|
134 | 0 | // Allow the timer to go away. |
135 | 0 | timer_ = nullptr; |
136 | 0 | return NS_OK; |
137 | 0 | } |
138 | | |
139 | | class nrappkitScheduledCallback : public nrappkitCallback { |
140 | | public: |
141 | | |
142 | | nrappkitScheduledCallback(NR_async_cb cb, void *cb_arg, |
143 | | const char *function, int line) |
144 | 0 | : nrappkitCallback(cb, cb_arg, function, line) {} |
145 | | |
146 | 0 | void Run() { |
147 | 0 | if (cb_) { |
148 | 0 | cb_(nullptr, 0, cb_arg_); |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | 0 | virtual void Cancel() override { |
153 | 0 | cb_ = nullptr; |
154 | 0 | } |
155 | | |
156 | 0 | ~nrappkitScheduledCallback() {} |
157 | | }; |
158 | | |
159 | | } // close namespace |
160 | | |
161 | | |
162 | | using namespace mozilla; |
163 | | |
164 | 0 | static nsCOMPtr<nsIEventTarget> GetSTSThread() { |
165 | 0 | nsresult rv; |
166 | 0 |
|
167 | 0 | nsCOMPtr<nsIEventTarget> sts_thread; |
168 | 0 |
|
169 | 0 | sts_thread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); |
170 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
171 | 0 |
|
172 | 0 | return sts_thread; |
173 | 0 | } |
174 | | |
175 | | // These timers must only be used from the STS thread. |
176 | | // This function is a helper that enforces that. |
177 | 0 | static void CheckSTSThread() { |
178 | 0 | DebugOnly<nsCOMPtr<nsIEventTarget>> sts_thread = GetSTSThread(); |
179 | 0 |
|
180 | 0 | ASSERT_ON_THREAD(sts_thread.value); |
181 | 0 | } |
182 | | |
183 | | static int nr_async_timer_set_zero(NR_async_cb cb, void *arg, |
184 | | char *func, int l, |
185 | 0 | nrappkitCallback **handle) { |
186 | 0 | nrappkitScheduledCallback* callback(new nrappkitScheduledCallback( |
187 | 0 | cb, arg, func, l)); |
188 | 0 |
|
189 | 0 | nsresult rv = GetSTSThread()->Dispatch(WrapRunnable( |
190 | 0 | nsAutoPtr<nrappkitScheduledCallback>(callback), |
191 | 0 | &nrappkitScheduledCallback::Run), |
192 | 0 | NS_DISPATCH_NORMAL); |
193 | 0 | if (NS_FAILED(rv)) |
194 | 0 | return R_FAILED; |
195 | 0 | |
196 | 0 | *handle = callback; |
197 | 0 |
|
198 | 0 | // On exit to this function, the only strong reference to callback is in |
199 | 0 | // the Runnable. Because we are redispatching to the same thread, |
200 | 0 | // this is always safe. |
201 | 0 | return 0; |
202 | 0 | } |
203 | | |
204 | | static int nr_async_timer_set_nonzero(int timeout, NR_async_cb cb, void *arg, |
205 | | char *func, int l, |
206 | 0 | nrappkitCallback **handle) { |
207 | 0 | nsresult rv; |
208 | 0 | CheckSTSThread(); |
209 | 0 |
|
210 | 0 | nrappkitTimerCallback* callback = |
211 | 0 | new nrappkitTimerCallback(cb, arg, func, l); |
212 | 0 |
|
213 | 0 | nsCOMPtr<nsITimer> timer; |
214 | 0 | rv = NS_NewTimerWithCallback(getter_AddRefs(timer), |
215 | 0 | callback, timeout, nsITimer::TYPE_ONE_SHOT); |
216 | 0 | if (NS_FAILED(rv)) { |
217 | 0 | return R_FAILED; |
218 | 0 | } |
219 | 0 |
|
220 | 0 | // Move the ownership of the timer to the callback object, which holds the |
221 | 0 | // timer alive per spec. |
222 | 0 | callback->SetTimer(timer.forget()); |
223 | 0 |
|
224 | 0 | *handle = callback; |
225 | 0 |
|
226 | 0 | return 0; |
227 | 0 | } |
228 | | |
229 | | int NR_async_timer_set(int timeout, NR_async_cb cb, void *arg, |
230 | 0 | char *func, int l, void **handle) { |
231 | 0 | CheckSTSThread(); |
232 | 0 |
|
233 | 0 | nrappkitCallback *callback; |
234 | 0 | int r; |
235 | 0 |
|
236 | 0 | if (!timeout) { |
237 | 0 | r = nr_async_timer_set_zero(cb, arg, func, l, &callback); |
238 | 0 | } else { |
239 | 0 | r = nr_async_timer_set_nonzero(timeout, cb, arg, func, l, &callback); |
240 | 0 | } |
241 | 0 |
|
242 | 0 | if (r) |
243 | 0 | return r; |
244 | 0 | |
245 | 0 | if (handle) |
246 | 0 | *handle = callback; |
247 | 0 |
|
248 | 0 | return 0; |
249 | 0 | } |
250 | | |
251 | 0 | int NR_async_schedule(NR_async_cb cb, void *arg, char *func, int l) { |
252 | 0 | // No need to check the thread because we check it next in the |
253 | 0 | // timer set. |
254 | 0 | return NR_async_timer_set(0, cb, arg, func, l, nullptr); |
255 | 0 | } |
256 | | |
257 | 0 | int NR_async_timer_cancel(void *handle) { |
258 | 0 | // Check for the handle being nonzero because sometimes we get |
259 | 0 | // no-op cancels that aren't on the STS thread. This can be |
260 | 0 | // non-racy as long as the upper-level code is careful. |
261 | 0 | if (!handle) |
262 | 0 | return 0; |
263 | 0 | |
264 | 0 | CheckSTSThread(); |
265 | 0 |
|
266 | 0 | nrappkitCallback* callback = static_cast<nrappkitCallback *>(handle); |
267 | 0 | callback->Cancel(); |
268 | 0 |
|
269 | 0 | return 0; |
270 | 0 | } |
271 | | |