Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(972)

Side by Side Diff: src/service_manager.cc

Issue 5333003: cashew: do not delete DBus::ObjectProxy objects from D-Bus callbacks (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/cashew.git@master
Patch Set: Address more djkurtz review comments Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« src/main.cc ('K') | « src/service_manager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/service_manager.h" 5 #include "src/service_manager.h"
6 6
7 #include <glog/logging.h> 7 #include <glog/logging.h>
8 8
9 #include "src/cashew_server.h" 9 #include "src/cashew_server.h"
10 #include "src/service.h" 10 #include "src/service.h"
(...skipping 15 matching lines...) Expand all
26 static const char *kFlimflamStateOnline = "online"; 26 static const char *kFlimflamStateOnline = "online";
27 27
28 // Flimflam service types 28 // Flimflam service types
29 static const char *kTypeCellular = "cellular"; 29 static const char *kTypeCellular = "cellular";
30 30
31 // GetFlimflamProperties retry interval 31 // GetFlimflamProperties retry interval
32 static const guint kSecondsPerMinute = 60; 32 static const guint kSecondsPerMinute = 60;
33 static const guint kGetFlimflamPropertiesIntervalSeconds = 33 static const guint kGetFlimflamPropertiesIntervalSeconds =
34 1 * kSecondsPerMinute; 34 1 * kSecondsPerMinute;
35 35
36 ServiceManager::ServiceManager(DBus::Connection& connection) // NOLINT 36 ServiceManager::ServiceManager(DBus::Connection& connection, // NOLINT
37 GMainLoop * const main_loop)
37 : DBus::ObjectProxy(connection, kFlimflamManagerPath, 38 : DBus::ObjectProxy(connection, kFlimflamManagerPath,
38 kFlimflamManagerName), 39 kFlimflamManagerName),
39 connection_(connection), cashew_server_(NULL), 40 connection_(connection), main_loop_(CHECK_NOTNULL(main_loop)),
40 default_technology_(Service::kTypeUnknown), 41 cashew_server_(NULL), default_technology_(Service::kTypeUnknown),
41 default_cellular_service_(NULL), 42 default_cellular_service_(NULL),
42 connectivity_state_(kConnectivityStateUnknown), 43 connectivity_state_(kConnectivityStateUnknown),
43 get_properties_source_id_(0), retrying_get_properties_(false) { 44 get_properties_source_id_(0), retrying_get_properties_(false),
45 deferred_service_deletion_source_id_(0) {
44 // schedule a GetProperties() call to Flimflam to init our state 46 // schedule a GetProperties() call to Flimflam to init our state
45 // we'll keep trying periodically until we succeed 47 // we'll keep trying periodically until we succeed
46 // we'll subsequently update this state by monitoring PropertyChanged signals 48 // we'll subsequently update this state by monitoring PropertyChanged signals
47 get_properties_source_id_ = 49 get_properties_source_id_ =
48 g_idle_add(StaticGetFlimflamPropertiesCallback, this); 50 g_idle_add(StaticGetFlimflamPropertiesCallback, this);
49 if (get_properties_source_id_ == 0) { 51 if (get_properties_source_id_ == 0) {
50 LOG(ERROR) << "ctor: g_idle_add failed"; 52 LOG(ERROR) << "ctor: g_idle_add failed";
51 } 53 }
52 } 54 }
53 55
54 ServiceManager::~ServiceManager() { 56 ServiceManager::~ServiceManager() {
57 DCHECK(!g_main_loop_is_running(main_loop_));
55 ClearDefaultCellularService(); 58 ClearDefaultCellularService();
56 DeleteServices(&services_); 59 // we're not in the main loop, so we can delete services immediately
60 bool defer = false;
61 DeleteServices(&services_, defer);
62 DeletePendingServices();
57 if (get_properties_source_id_ != 0 && 63 if (get_properties_source_id_ != 0 &&
58 !g_source_remove(get_properties_source_id_)) { 64 !g_source_remove(get_properties_source_id_)) {
59 DLOG(WARNING) << "dtor: g_source_remove failed"; 65 DLOG(WARNING) << "dtor: g_source_remove failed for source id "
66 << get_properties_source_id_;
67 }
68 if (deferred_service_deletion_source_id_ != 0 &&
69 !g_source_remove(deferred_service_deletion_source_id_)) {
70 DLOG(WARNING) << "dtor: g_source_remove failed for source id "
71 << deferred_service_deletion_source_id_;
60 } 72 }
61 } 73 }
62 74
63 const Service* ServiceManager::GetService(const std::string& service_path) 75 const Service* ServiceManager::GetService(const std::string& service_path)
64 const { 76 const {
65 ServiceMap::const_iterator it = services_.find(service_path); 77 ServiceMap::const_iterator it = services_.find(service_path);
66 if (it == services_.end()) { 78 if (it == services_.end()) {
67 return NULL; 79 return NULL;
68 } 80 }
69 DCHECK(it->second != NULL); 81 DCHECK(it->second != NULL);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 } 174 }
163 175
164 bool ServiceManager::RetryingGetProperties() const { 176 bool ServiceManager::RetryingGetProperties() const {
165 return retrying_get_properties_; 177 return retrying_get_properties_;
166 } 178 }
167 179
168 void ServiceManager::OnRetryingGetProperties(bool retrying) { 180 void ServiceManager::OnRetryingGetProperties(bool retrying) {
169 retrying_get_properties_ = retrying; 181 retrying_get_properties_ = retrying;
170 } 182 }
171 183
184 guint ServiceManager::GetDeferredServiceDeletionSourceId() const {
185 return deferred_service_deletion_source_id_;
186 }
187
188 void ServiceManager::SetDeferredServiceDeletionSourceId(guint source_id) {
189 deferred_service_deletion_source_id_ = source_id;
190 }
191
172 // Private methods 192 // Private methods
173 193
174 void ServiceManager::DeleteServices(ServiceMap *service_map) { 194 void ServiceManager::DeleteServices(ServiceMap *service_map, bool defer) {
195 DLOG(INFO) << "DeleteServices: defer = " << defer;
175 DCHECK(service_map != NULL); 196 DCHECK(service_map != NULL);
176 while (!service_map->empty()) { 197 while (!service_map->empty()) {
177 const std::string& path =
178 static_cast<std::string>(service_map->begin()->first);
179 DLOG(INFO) << "DeleteServices: deleting service: " << path;
180 Service *service = static_cast<Service *>(service_map->begin()->second); 198 Service *service = static_cast<Service *>(service_map->begin()->second);
181 DCHECK(service != NULL); 199 DCHECK(service != NULL);
182 DCHECK(service != default_cellular_service_); 200 DCHECK(service != default_cellular_service_);
183 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL); 201 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL);
184 delete service; 202 if (defer) {
203 DLOG(INFO) << "DeleteServices: scheduling service for later deletion: "
204 << service->GetPath();
205 ScheduleServiceForLaterDeletion(service);
206 } else {
207 DLOG(INFO) << "DeleteServices: deleting service: " << service->GetPath();
208 delete service;
209 }
185 service_map->erase(service_map->begin()); 210 service_map->erase(service_map->begin());
186 } 211 }
187 } 212 }
188 213
214 void ServiceManager::DeletePendingServices() {
215 while (!services_pending_deletion_.empty()) {
216 Service *service = *(services_pending_deletion_.begin());
217 DCHECK(service != NULL);
218 DLOG(INFO) << "DeletePendingServices: deleting service: "
219 << service->GetPath();
220 DCHECK(service != default_cellular_service_);
221 delete service;
222 services_pending_deletion_.erase(services_pending_deletion_.begin());
223 }
224 }
225
226 void ServiceManager::ScheduleServiceForLaterDeletion(Service *service) {
227 DCHECK(service != NULL);
228 DCHECK(service != default_cellular_service_);
229 // we might be inside of a D-Bus callback.
230 // add the service to our |services_pending_deletion_| list, and schedule a
231 // glib callback to delete these services later from the main loop if such
232 // a callback is not already scheduled
233 services_pending_deletion_.push_back(service);
234 if (deferred_service_deletion_source_id_ != 0) {
235 return;
236 }
237 deferred_service_deletion_source_id_ =
238 g_idle_add(StaticDeletePendingServicesCallback, this);
239 if (deferred_service_deletion_source_id_ == 0) {
240 LOG(ERROR) << "ScheduleServiceForLaterDeletion: g_idle_add failed";
241 return;
242 }
243 }
244
245 // static
246 gboolean ServiceManager::StaticDeletePendingServicesCallback(gpointer data) {
247 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data);
248 DCHECK(service_manager != NULL);
249 DCHECK_NE(service_manager->GetDeferredServiceDeletionSourceId(), 0);
250 service_manager->DeletePendingServices();
251 // we don't want to be run again automatically
252 // DeleteServiceOrScheduleForLaterDeletion will schedule us as needed
253 service_manager->SetDeferredServiceDeletionSourceId(0);
254 return FALSE;
255 }
256
189 // static 257 // static
190 gboolean ServiceManager::StaticGetFlimflamPropertiesCallback(gpointer data) { 258 gboolean ServiceManager::StaticGetFlimflamPropertiesCallback(gpointer data) {
191 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data); 259 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data);
192 CHECK_NOTNULL(service_manager); 260 CHECK_NOTNULL(service_manager);
193 DCHECK_NE(service_manager->GetGetPropertiesSourceId(), 0); 261 DCHECK_NE(service_manager->GetGetPropertiesSourceId(), 0);
194 if (!service_manager->GetFlimflamProperties()) { 262 if (!service_manager->GetFlimflamProperties()) {
195 // call failed, so try again later 263 // call failed, so try again later
196 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: " 264 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: "
197 << "GetFlimflamProperties failed, will retry in " 265 << "GetFlimflamProperties failed, will retry in "
198 << kGetFlimflamPropertiesIntervalSeconds << " secs"; 266 << kGetFlimflamPropertiesIntervalSeconds << " secs";
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 380
313 ServiceMap::iterator old_it = old_services.find(path); 381 ServiceMap::iterator old_it = old_services.find(path);
314 if (old_it != old_services.end()) { 382 if (old_it != old_services.end()) {
315 // service is old: move it from old_services to services_ 383 // service is old: move it from old_services to services_
316 Service *service = static_cast<Service *>(old_it->second); 384 Service *service = static_cast<Service *>(old_it->second);
317 DCHECK(service != NULL); 385 DCHECK(service != NULL);
318 old_services.erase(old_it); 386 old_services.erase(old_it);
319 services_[path] = service; 387 services_[path] = service;
320 } else { 388 } else {
321 // service is new: create a Service obj for it and add it to services_ 389 // service is new: create a Service obj for it and add it to services_
390 // TODO(vlaviano): If a service went away and came back immediately, there
391 // might still be a corresponding service object pending deletion. We
392 // could rescue it rather than allocating a new object here.
322 OnNewService(path); 393 OnNewService(path);
323 } 394 }
324 } 395 }
325 396
326 // clear default service if it failed to appear in the update and we're 397 // clear default service if it failed to appear in the update and we're
327 // about to delete it 398 // about to delete it
328 if (default_cellular_service_ != NULL) { 399 if (default_cellular_service_ != NULL) {
329 ServiceMap::const_iterator it = 400 ServiceMap::const_iterator it =
330 old_services.find(default_cellular_service_->GetPath()); 401 old_services.find(default_cellular_service_->GetPath());
331 if (it != old_services.end()) { 402 if (it != old_services.end()) {
332 ClearDefaultCellularService(); 403 ClearDefaultCellularService();
333 } 404 }
334 } 405 }
335 406
336 // services left in old_services failed to appear in the update: delete them 407 // services left in old_services failed to appear in the update: delete them
337 DeleteServices(&old_services); 408 // NOTE: We're in a D-Bus callback so we can't delete these services
409 // immediately without triggering a potential deadlock. We schedule them for
410 // deferred deletion.
411 bool defer = true;
412 DeleteServices(&old_services, defer);
338 413
339 // Flimflam always places the default service first in its list of services, 414 // Flimflam always places the default service first in its list of services,
340 // so we'll take a look at the first element in the paths list and see if the 415 // so we'll take a look at the first element in the paths list and see if the
341 // default service has changed. Note that |paths| can be empty. We still want 416 // default service has changed. Note that |paths| can be empty. We still want
342 // to know about this, since it means that there is no default service. 417 // to know about this, since it means that there is no default service.
343 const DBus::Path *default_service_path = NULL; 418 const DBus::Path *default_service_path = NULL;
344 if (!paths.empty()) { 419 if (!paths.empty()) {
345 default_service_path = &*paths.begin(); 420 default_service_path = &*paths.begin();
346 } 421 }
347 OnDefaultServiceUpdate(default_service_path); 422 OnDefaultServiceUpdate(default_service_path);
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 // notify our child services 506 // notify our child services
432 ServiceMap::iterator it; 507 ServiceMap::iterator it;
433 for (it = services_.begin(); it != services_.end(); ++it) { 508 for (it = services_.begin(); it != services_.end(); ++it) {
434 Service *service = static_cast<Service*>(it->second); 509 Service *service = static_cast<Service*>(it->second);
435 DCHECK(service != NULL); 510 DCHECK(service != NULL);
436 service->OnFlimflamOffline(); 511 service->OnFlimflamOffline();
437 } 512 }
438 } 513 }
439 514
440 } // namespace cashew 515 } // namespace cashew
OLDNEW
« src/main.cc ('K') | « src/service_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698