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

Side by Side Diff: src/service.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, 1 month 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
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.h" 5 #include "src/service.h"
6 6
7 #include <glog/logging.h> 7 #include <glog/logging.h>
8 8
9 #include "src/data_plan_provider.h" 9 #include "src/data_plan_provider.h"
10 #include "src/device.h" 10 #include "src/device.h"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 Service::Service(ServiceManager * const parent, 76 Service::Service(ServiceManager * const parent,
77 DBus::Connection& connection, // NOLINT 77 DBus::Connection& connection, // NOLINT
78 const DBus::Path& path) 78 const DBus::Path& path)
79 : DBus::ObjectProxy(connection, path, kFlimflamServiceName), 79 : DBus::ObjectProxy(connection, path, kFlimflamServiceName),
80 parent_(CHECK_NOTNULL(parent)), connection_(connection), path_(path), 80 parent_(CHECK_NOTNULL(parent)), connection_(connection), path_(path),
81 state_(kStateUnknown), type_(kTypeUnknown), device_(NULL), 81 state_(kStateUnknown), type_(kTypeUnknown), device_(NULL),
82 provider_(NULL), request_in_progress_(false), 82 provider_(NULL), request_in_progress_(false),
83 update_timeout_source_(NULL), policy_(NULL), 83 update_timeout_source_(NULL), policy_(NULL),
84 is_default_service_(false), get_properties_source_id_(0), 84 is_default_service_(false), get_properties_source_id_(0),
85 retrying_get_properties_(false), 85 retrying_get_properties_(false),
86 connectivity_state_(kConnectivityStateUnknown) { 86 connectivity_state_(kConnectivityStateUnknown),
87 deferred_device_deletion_source_id_(0) {
87 // schedule a GetProperties() call to our Flimflam service path to init state 88 // schedule a GetProperties() call to our Flimflam service path to init state
88 // we'll keep trying periodically until we succeed 89 // we'll keep trying periodically until we succeed
89 // we'll subsequently update this state by monitoring PropertyChanged signals 90 // we'll subsequently update this state by monitoring PropertyChanged signals
90 get_properties_source_id_ = 91 get_properties_source_id_ =
91 g_idle_add(StaticGetServicePropertiesCallback, this); 92 g_idle_add(StaticGetServicePropertiesCallback, this);
92 if (get_properties_source_id_ == 0) { 93 if (get_properties_source_id_ == 0) {
93 LOG(ERROR) << path_ << ": ctor: g_idle_add failed"; 94 LOG(ERROR) << path_ << ": ctor: g_idle_add failed";
94 } 95 }
95 } 96 }
96 97
97 Service::~Service() { 98 Service::~Service() {
98 DeleteCarrierState(); 99 DeleteCarrierState();
99 DeleteDataPlans(&data_plans_); 100 DeleteDataPlans(&data_plans_);
101 // ServiceManager ensures that this dtor is not being called from within a
102 // D-Bus callback, so it's ok to delete |device_| and any members of
103 // |devices_pending_deletion_| directly.
100 if (device_ != NULL) { 104 if (device_ != NULL) {
101 DLOG(INFO) << path_ << ": deleting device " << device_->GetPath(); 105 DLOG(INFO) << path_ << ": dtor: deleting device " << device_->GetPath();
102 delete device_; 106 delete device_;
103 device_ = NULL; 107 device_ = NULL;
104 } 108 }
109 DeletePendingDevices();
105 if (get_properties_source_id_ != 0 && 110 if (get_properties_source_id_ != 0 &&
106 !g_source_remove(get_properties_source_id_)) { 111 !g_source_remove(get_properties_source_id_)) {
107 DLOG(WARNING) << path_ << ": dtor: g_source_remove failed"; 112 DLOG(WARNING) << path_ << ": dtor: g_source_remove failed for source id "
113 << get_properties_source_id_;
114 }
115 if (deferred_device_deletion_source_id_ != 0 &&
116 !g_source_remove(deferred_device_deletion_source_id_)) {
117 DLOG(WARNING) << path_ << ": dtor: g_source_remove failed for source id "
118 << deferred_device_deletion_source_id_;
108 } 119 }
109 } 120 }
110 121
111 const DBus::Path& Service::GetPath() const { 122 const DBus::Path& Service::GetPath() const {
112 return path_; 123 return path_;
113 } 124 }
114 125
115 Service::State Service::GetState() const { 126 Service::State Service::GetState() const {
116 return state_; 127 return state_;
117 } 128 }
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 } 454 }
444 455
445 bool Service::RetryingGetProperties() const { 456 bool Service::RetryingGetProperties() const {
446 return retrying_get_properties_; 457 return retrying_get_properties_;
447 } 458 }
448 459
449 void Service::OnRetryingGetProperties(bool retrying) { 460 void Service::OnRetryingGetProperties(bool retrying) {
450 retrying_get_properties_ = retrying; 461 retrying_get_properties_ = retrying;
451 } 462 }
452 463
464 guint Service::GetDeferredDeviceDeletionSourceId() const {
465 return deferred_device_deletion_source_id_;
466 }
467
468 void Service::SetDeferredDeviceDeletionSourceId(guint source_id) {
469 deferred_device_deletion_source_id_ = source_id;
470 }
471
453 // Private methods 472 // Private methods
454 473
474 void Service::DeletePendingDevices() {
475 while (!devices_pending_deletion_.empty()) {
476 Device *device = *(devices_pending_deletion_.begin());
477 DCHECK(device != NULL);
478 DLOG(INFO) << path_ << ": DeletePendingDevices: deleting device: "
479 << device->GetPath();
480 DCHECK(device != device_);
481 delete device;
482 devices_pending_deletion_.erase(devices_pending_deletion_.begin());
483 }
484 }
485
486 void Service::ScheduleDeviceForLaterDeletion(Device *device) {
487 DCHECK(device != NULL);
488 DCHECK(device != device_);
489 // We might be inside of a D-Bus callback. We add the device to our
490 // |devices_pending_deletion_| list and schedule a glib callback to
491 // delete these devices from the main loop if one is not already
492 // scheduled.
493 DLOG(INFO) << path_ << ": ScheduleDeviceForLaterDeletion: "
494 << device->GetPath();
495 devices_pending_deletion_.push_back(device);
496 if (deferred_device_deletion_source_id_ != 0) {
497 DLOG(INFO) << path_ << ": ScheduleDeviceForLaterDeletion: "
498 << "deferred device deletion callback already scheduled";
499 return;
500 }
501 deferred_device_deletion_source_id_ =
502 g_idle_add(StaticDeletePendingDevicesCallback, this);
503 if (deferred_device_deletion_source_id_ == 0) {
504 LOG(ERROR) << path_
505 << ": ScheduleDeviceForLaterDeletion: g_idle_add failed";
506 return;
507 }
508 DLOG(INFO) << path_ << ": ScheduleDeviceForLaterDeletion: "
509 << "scheduled deferred device deletion callback";
510 }
511
512 // static
513 gboolean Service::StaticDeletePendingDevicesCallback(gpointer data) {
514 Service *service = reinterpret_cast<Service*>(data);
515 DCHECK(service != NULL);
516 DCHECK_NE(service->GetDeferredDeviceDeletionSourceId(), 0);
517 service->DeletePendingDevices();
518 // we don't want to be run again automatically
519 // ScheduleDeviceForLaterDeletion will schedule us as needed
520 service->SetDeferredDeviceDeletionSourceId(0);
521 return FALSE;
522 }
523
455 // static 524 // static
456 Service::ConnectivityState Service::ConnectivityStateFromString( 525 Service::ConnectivityState Service::ConnectivityStateFromString(
457 const std::string& connectivity_state) { 526 const std::string& connectivity_state) {
458 if (connectivity_state == kFlimflamServiceConnectivityStateUnknown) { 527 if (connectivity_state == kFlimflamServiceConnectivityStateUnknown) {
459 return kConnectivityStateUnknown; 528 return kConnectivityStateUnknown;
460 } 529 }
461 if (connectivity_state == kFlimflamServiceConnectivityStateRestricted) { 530 if (connectivity_state == kFlimflamServiceConnectivityStateRestricted) {
462 return kConnectivityStateRestricted; 531 return kConnectivityStateRestricted;
463 } 532 }
464 if (connectivity_state == kFlimflamServiceConnectivityStateUnrestricted) { 533 if (connectivity_state == kFlimflamServiceConnectivityStateUnrestricted) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 } 569 }
501 570
502 void Service::OnDeviceUpdate(const DBus::Path& device_path) { 571 void Service::OnDeviceUpdate(const DBus::Path& device_path) {
503 DLOG(INFO) << path_ << ": OnDeviceUpdate: device_path = " << device_path; 572 DLOG(INFO) << path_ << ": OnDeviceUpdate: device_path = " << device_path;
504 573
505 // if there's an existing device with a non-matching path: destroy it and 574 // if there's an existing device with a non-matching path: destroy it and
506 // fall through to make a new one below. 575 // fall through to make a new one below.
507 if (device_ != NULL && device_->GetPath() != device_path) { 576 if (device_ != NULL && device_->GetPath() != device_path) {
508 LOG(WARNING) << path_ << ": OnDeviceUpdate: device path changed from " 577 LOG(WARNING) << path_ << ": OnDeviceUpdate: device path changed from "
509 << device_->GetPath() << " to " << device_path; 578 << device_->GetPath() << " to " << device_path;
510 delete device_; 579 // We might be in a D-Bus callback, so schedule device for later deletion
580 // to avoid possible deadlock. See the comments in service_manager.h and
581 // service_manager.cc for more on this issue.
582 Device *device_to_delete = device_;
511 device_ = NULL; 583 device_ = NULL;
584 ScheduleDeviceForLaterDeletion(device_to_delete);
512 } 585 }
513 586
514 // if there's an existing device with matching path: all is well 587 // if there's an existing device with matching path: all is well
515 if (device_ != NULL) { 588 if (device_ != NULL) {
516 return; 589 return;
517 } 590 }
518 591
519 // if there's no existing device: make one 592 // if there's no existing device: make one
520 device_ = new(std::nothrow) Device(this, connection_, device_path); 593 device_ = new(std::nothrow) Device(this, connection_, device_path);
521 if (device_ == NULL) { 594 if (device_ == NULL) {
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
915 DCHECK(policy_ != NULL); 988 DCHECK(policy_ != NULL);
916 if (policy_->ShouldEmitDataPlansUpdate(data_plans_)) { 989 if (policy_->ShouldEmitDataPlansUpdate(data_plans_)) {
917 DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: sending update"; 990 DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: sending update";
918 parent_->EmitDataPlansUpdate(*this); 991 parent_->EmitDataPlansUpdate(*this);
919 } else { 992 } else {
920 DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: not sending update"; 993 DLOG(INFO) << path_ << ": MaybeEmitDataPlansUpdate: not sending update";
921 } 994 }
922 } 995 }
923 996
924 } // namespace cashew 997 } // namespace cashew
OLDNEW
« src/main.cc ('K') | « src/service.h ('k') | src/service_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698