Line data Source code
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 "nsITimer.h"
59 : #include "nsNetCID.h"
60 : #include "runnable_utils.h"
61 : #include "mozilla/DebugOnly.h"
62 :
63 : extern "C" {
64 : #include "nr_api.h"
65 : #include "async_timer.h"
66 : }
67 :
68 :
69 : namespace mozilla {
70 :
71 : class nrappkitCallback {
72 : public:
73 0 : nrappkitCallback(NR_async_cb cb, void *cb_arg,
74 : const char *function, int line)
75 0 : : cb_(cb), cb_arg_(cb_arg), function_(function), line_(line) {
76 0 : }
77 0 : virtual ~nrappkitCallback() {}
78 :
79 : virtual void Cancel() = 0;
80 :
81 : protected:
82 : /* additional members */
83 : NR_async_cb cb_;
84 : void *cb_arg_;
85 : std::string function_;
86 : int line_;
87 : };
88 :
89 : class nrappkitTimerCallback : public nrappkitCallback,
90 : public nsITimerCallback {
91 : public:
92 : // We're going to release ourself in the callback, so we need to be threadsafe
93 : NS_DECL_THREADSAFE_ISUPPORTS
94 : NS_DECL_NSITIMERCALLBACK
95 :
96 0 : nrappkitTimerCallback(NR_async_cb cb, void *cb_arg,
97 : const char *function, int line)
98 0 : : nrappkitCallback(cb, cb_arg, function, line),
99 0 : timer_(nullptr) {}
100 :
101 0 : void SetTimer(already_AddRefed<nsITimer>&& timer) {
102 0 : timer_ = timer;
103 0 : }
104 :
105 0 : virtual void Cancel() override {
106 0 : AddRef(); // Cancelling the timer causes the callback it holds to
107 : // be released. AddRef() keeps us alive.
108 0 : timer_->Cancel();
109 0 : timer_ = nullptr;
110 0 : Release(); // Will cause deletion of this object.
111 0 : }
112 :
113 : private:
114 : nsCOMPtr<nsITimer> timer_;
115 0 : virtual ~nrappkitTimerCallback() {}
116 : };
117 :
118 0 : NS_IMPL_ISUPPORTS(nrappkitTimerCallback, nsITimerCallback)
119 :
120 0 : NS_IMETHODIMP nrappkitTimerCallback::Notify(nsITimer *timer) {
121 0 : r_log(LOG_GENERIC, LOG_DEBUG, "Timer callback fired (set in %s:%d)",
122 0 : function_.c_str(), line_);
123 0 : MOZ_RELEASE_ASSERT(timer == timer_);
124 0 : cb_(nullptr, 0, cb_arg_);
125 :
126 : // Allow the timer to go away.
127 0 : timer_ = nullptr;
128 0 : return NS_OK;
129 : }
130 :
131 : class nrappkitScheduledCallback : public nrappkitCallback {
132 : public:
133 :
134 0 : nrappkitScheduledCallback(NR_async_cb cb, void *cb_arg,
135 : const char *function, int line)
136 0 : : nrappkitCallback(cb, cb_arg, function, line) {}
137 :
138 0 : void Run() {
139 0 : if (cb_) {
140 0 : cb_(nullptr, 0, cb_arg_);
141 : }
142 0 : }
143 :
144 0 : virtual void Cancel() override {
145 0 : cb_ = nullptr;
146 0 : }
147 :
148 0 : ~nrappkitScheduledCallback() {}
149 : };
150 :
151 : } // close namespace
152 :
153 :
154 : using namespace mozilla;
155 :
156 0 : static nsCOMPtr<nsIEventTarget> GetSTSThread() {
157 : nsresult rv;
158 :
159 0 : nsCOMPtr<nsIEventTarget> sts_thread;
160 :
161 0 : sts_thread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
162 0 : MOZ_ASSERT(NS_SUCCEEDED(rv));
163 :
164 0 : return sts_thread;
165 : }
166 :
167 : // These timers must only be used from the STS thread.
168 : // This function is a helper that enforces that.
169 0 : static void CheckSTSThread() {
170 0 : DebugOnly<nsCOMPtr<nsIEventTarget>> sts_thread = GetSTSThread();
171 :
172 0 : ASSERT_ON_THREAD(sts_thread.value);
173 0 : }
174 :
175 0 : static int nr_async_timer_set_zero(NR_async_cb cb, void *arg,
176 : char *func, int l,
177 : nrappkitCallback **handle) {
178 : nrappkitScheduledCallback* callback(new nrappkitScheduledCallback(
179 0 : cb, arg, func, l));
180 :
181 0 : nsresult rv = GetSTSThread()->Dispatch(WrapRunnable(
182 0 : nsAutoPtr<nrappkitScheduledCallback>(callback),
183 : &nrappkitScheduledCallback::Run),
184 0 : NS_DISPATCH_NORMAL);
185 0 : if (NS_FAILED(rv))
186 0 : return R_FAILED;
187 :
188 0 : *handle = callback;
189 :
190 : // On exit to this function, the only strong reference to callback is in
191 : // the Runnable. Because we are redispatching to the same thread,
192 : // this is always safe.
193 0 : return 0;
194 : }
195 :
196 0 : static int nr_async_timer_set_nonzero(int timeout, NR_async_cb cb, void *arg,
197 : char *func, int l,
198 : nrappkitCallback **handle) {
199 : nsresult rv;
200 0 : CheckSTSThread();
201 :
202 0 : nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
203 0 : if (NS_FAILED(rv)) {
204 0 : return(R_FAILED);
205 : }
206 :
207 : nrappkitTimerCallback* callback =
208 0 : new nrappkitTimerCallback(cb, arg, func, l);
209 0 : rv = timer->InitWithCallback(callback, timeout, nsITimer::TYPE_ONE_SHOT);
210 0 : if (NS_FAILED(rv)) {
211 0 : return R_FAILED;
212 : }
213 :
214 : // Move the ownership of the timer to the callback object, which holds the
215 : // timer alive per spec.
216 0 : callback->SetTimer(timer.forget());
217 :
218 0 : *handle = callback;
219 :
220 0 : return 0;
221 : }
222 :
223 0 : int NR_async_timer_set(int timeout, NR_async_cb cb, void *arg,
224 : char *func, int l, void **handle) {
225 0 : CheckSTSThread();
226 :
227 : nrappkitCallback *callback;
228 : int r;
229 :
230 0 : if (!timeout) {
231 0 : r = nr_async_timer_set_zero(cb, arg, func, l, &callback);
232 : } else {
233 0 : r = nr_async_timer_set_nonzero(timeout, cb, arg, func, l, &callback);
234 : }
235 :
236 0 : if (r)
237 0 : return r;
238 :
239 0 : if (handle)
240 0 : *handle = callback;
241 :
242 0 : return 0;
243 : }
244 :
245 0 : int NR_async_schedule(NR_async_cb cb, void *arg, char *func, int l) {
246 : // No need to check the thread because we check it next in the
247 : // timer set.
248 0 : return NR_async_timer_set(0, cb, arg, func, l, nullptr);
249 : }
250 :
251 0 : int NR_async_timer_cancel(void *handle) {
252 : // Check for the handle being nonzero because sometimes we get
253 : // no-op cancels that aren't on the STS thread. This can be
254 : // non-racy as long as the upper-level code is careful.
255 0 : if (!handle)
256 0 : return 0;
257 :
258 0 : CheckSTSThread();
259 :
260 0 : nrappkitCallback* callback = static_cast<nrappkitCallback *>(handle);
261 0 : callback->Cancel();
262 :
263 0 : return 0;
264 : }
265 :
|