1 : // Copyright 2013 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/trace/common/service.h"
16 :
17 : #include "base/logging.h"
18 :
19 : namespace trace {
20 : namespace common {
21 :
22 : Service::Service(const base::StringPiece16& name)
23 : : name_(name.begin(), name.end()),
24 : state_(kUnused),
25 E : owning_thread_id_(base::PlatformThread::CurrentId()) {
26 E : DCHECK(!name.empty());
27 E : }
28 :
29 E : Service::~Service() {
30 E : }
31 :
32 E : void Service::set_instance_id(const base::StringPiece16& instance_id) {
33 E : DCHECK_EQ(kUnused, state_);
34 E : instance_id_.assign(instance_id.begin(), instance_id.end());
35 E : }
36 :
37 E : void Service::set_started_callback(ServiceCallback callback) {
38 E : DCHECK_EQ(kUnused, state_);
39 E : started_callback_ = callback;
40 E : }
41 :
42 E : void Service::set_interrupted_callback(ServiceCallback callback) {
43 E : DCHECK_EQ(kUnused, state_);
44 E : interrupted_callback_ = callback;
45 E : }
46 :
47 E : void Service::set_stopped_callback(ServiceCallback callback) {
48 E : DCHECK_EQ(kUnused, state_);
49 E : stopped_callback_ = callback;
50 E : }
51 :
52 E : Service::State Service::state() {
53 : // This is only safe as reading and writing to a 32-bit value is atomic on
54 : // x86. Otherwise we'd need a lock here.
55 E : return state_;
56 E : }
57 :
58 E : bool Service::Start() {
59 E : DCHECK_EQ(owning_thread_id_, base::PlatformThread::CurrentId());
60 E : DCHECK_EQ(kUnused, state_);
61 :
62 E : LOG(INFO) << "Starting the " << name_ << " service with instance ID \""
63 : << instance_id_ << "\".";
64 :
65 E : if (!StartImpl()) {
66 E : LOG(ERROR) << "Failed to stop " << name_ << " service with instance ID \""
67 : << instance_id_ << "\".";
68 E : set_state(kErrored);
69 E : return false;
70 : }
71 :
72 E : return true;
73 E : }
74 :
75 E : bool Service::Stop() {
76 E : DCHECK_NE(kErrored, state_);
77 :
78 : // No need to try to stop things again.
79 E : if (state_ == kStopping || state_ == kStopped)
80 i : return true;
81 :
82 E : LOG(INFO) << "Stopping the " << name_ << " service with instance ID \""
83 : << instance_id_ << "\".";
84 :
85 E : set_state(kStopping);
86 :
87 E : if (!StopImpl()) {
88 E : LOG(ERROR) << "Failed to stop " << name_ << " service with instance ID \""
89 : << instance_id_ << "\".";
90 E : set_state(kErrored);
91 E : return false;
92 : }
93 :
94 E : return true;
95 E : }
96 :
97 E : bool Service::Join() {
98 E : DCHECK_EQ(owning_thread_id_, base::PlatformThread::CurrentId());
99 E : DCHECK_NE(kErrored, state_);
100 :
101 E : LOG(INFO) << "Joining the " << name_ << " service with instance ID \""
102 : << instance_id_ << "\".";
103 :
104 E : if (!JoinImpl()) {
105 i : LOG(ERROR) << "Failed to join " << name_ << " service with instance ID \""
106 : << instance_id_ << "\".";
107 i : set_state(kErrored);
108 i : return false;
109 : }
110 :
111 : // We expect the service implementation to have transitioned us to the stopped
112 : // state as it finished work.
113 E : DCHECK_EQ(kStopped, state_);
114 :
115 E : return true;
116 E : }
117 :
118 E : bool Service::OnInitialized() {
119 E : DCHECK_EQ(kUnused, state_);
120 E : set_state(kInitialized);
121 E : return true;
122 E : }
123 :
124 E : bool Service::OnStarted() {
125 E : DCHECK_EQ(kInitialized, state_);
126 E : if (!started_callback_.is_null() && !started_callback_.Run(this))
127 i : return false;
128 E : set_state(kRunning);
129 E : return true;
130 E : }
131 :
132 E : bool Service::OnInterrupted() {
133 : // A service can be interrupted from another thread, another instance of
134 : // Service, another process, etc. Thus, it's completely valid for a Service
135 : // instance to be interrupted in most any state, except stopped or in error.
136 E : DCHECK(state_ != kStopped && state_ != kErrored);
137 E : if (!interrupted_callback_.is_null() && !interrupted_callback_.Run(this))
138 E : return false;
139 E : return true;
140 E : }
141 :
142 E : bool Service::OnStopped() {
143 E : DCHECK_EQ(kStopping, state_);
144 E : if (!stopped_callback_.is_null() && !stopped_callback_.Run(this))
145 i : return false;
146 E : set_state(kStopped);
147 E : return true;
148 E : }
149 :
150 E : void Service::set_state(State state) {
151 : // This is only safe because writing to state_ is atomic, otherwise we'd
152 : // have to use a lock here.
153 E : OnStateChange(state_, state);
154 E : state_ = state;
155 E : }
156 :
157 : } // namespace common
158 : } // namespace trace
|