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

Side by Side Diff: chrome/browser/in_process_webkit/indexed_db_key_utility_client.cc

Issue 6209005: Fix IndexedDB race condition during shutdown. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressing Jeremy's comments Created 9 years, 11 months 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) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium 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 "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h" 5 #include "chrome/browser/in_process_webkit/indexed_db_key_utility_client.h"
6 6
7 #include <vector> 7 #include "base/lazy_instance.h"
8 8 #include "base/synchronization/waitable_event.h"
9 #include "chrome/browser/browser_process.h" 9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/utility_process_host.h"
10 #include "chrome/common/indexed_db_key.h" 11 #include "chrome/common/indexed_db_key.h"
11 #include "chrome/common/serialized_script_value.h" 12 #include "chrome/common/serialized_script_value.h"
12 13
14 // This class is used to obtain IndexedDBKeys from SerializedScriptValues
15 // given an IDBKeyPath. It uses UtilityProcess to do this inside a sandbox
16 // (a V8 lock is required there). At this level, all methods are synchronous
17 // as required by the caller. The public API is used on WEBKIT thread,
18 // but internally it moves around to UI and IO as needed.
19 class KeyUtilityClientImpl
20 : public base::RefCountedThreadSafe<KeyUtilityClientImpl> {
21 public:
22 KeyUtilityClientImpl();
23
24 // Starts the UtilityProcess. Must be called before any other method.
25 void StartUtilityProcess();
26
27 // Stops the UtilityProcess. No further keys can be created after this.
28 void Shutdown();
29
30 // Synchronously obtain the |keys| from |values| for the given |key_path|.
31 void CreateIDBKeysFromSerializedValuesAndKeyPath(
32 const std::vector<SerializedScriptValue>& values,
33 const string16& key_path,
34 std::vector<IndexedDBKey>* keys);
35
36 private:
37 class Client : public UtilityProcessHost::Client {
38 public:
39 explicit Client(KeyUtilityClientImpl* parent);
40
41 // UtilityProcessHost::Client
42 virtual void OnProcessCrashed(int exit_code);
43 virtual void OnIDBKeysFromValuesAndKeyPathSucceeded(
44 int id, const std::vector<IndexedDBKey>& keys);
45 virtual void OnIDBKeysFromValuesAndKeyPathFailed(int id);
46
47 private:
48 KeyUtilityClientImpl* parent_;
49
50 DISALLOW_COPY_AND_ASSIGN(Client);
51 };
52
53 friend class base::RefCountedThreadSafe<KeyUtilityClientImpl>;
54 ~KeyUtilityClientImpl();
55
56 void GetRDHAndStartUtilityProcess();
57 void StartUtilityProcessInternal(ResourceDispatcherHost* rdh);
58 void EndUtilityProcessInternal();
59 void CallStartIDBKeyFromValueAndKeyPathFromIOThread(
60 const std::vector<SerializedScriptValue>& values,
61 const string16& key_path);
62
63 void SetKeys(const std::vector<IndexedDBKey>& keys);
64 void FinishCreatingKeys();
65
66 base::WaitableEvent waitable_event_;
67
68 // Used in both IO and WEBKIT threads, but guarded by WaitableEvent, i.e.,
69 // these members are only set / read when the other thread is blocked.
70 enum State {
71 STATE_UNINITIALIZED,
72 STATE_INITIALIZED,
73 STATE_CREATING_KEYS,
74 STATE_SHUTDOWN,
75 };
76 State state_;
77 std::vector<IndexedDBKey> keys_;
78
79 // Used in the IO thread.
80 UtilityProcessHost* utility_process_host_;
81 scoped_refptr<Client> client_;
82
83 DISALLOW_COPY_AND_ASSIGN(KeyUtilityClientImpl);
84 };
85
86 // IndexedDBKeyUtilityClient definitions.
87
88 static base::LazyInstance<IndexedDBKeyUtilityClient> client_instance(
89 base::LINKER_INITIALIZED);
90
13 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient() 91 IndexedDBKeyUtilityClient::IndexedDBKeyUtilityClient()
92 : is_shutdown_(false) {
93 // Note that creating the impl_ object is deferred until it is first needed,
94 // as this class can be constructed even though it never gets used.
95 }
96
97 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() {
98 DCHECK(!impl_ || is_shutdown_);
99 }
100
101 // static
102 void IndexedDBKeyUtilityClient::Shutdown() {
103 IndexedDBKeyUtilityClient* instance = client_instance.Pointer();
104 if (!instance->impl_)
105 return;
106
107 instance->is_shutdown_ = true;
108 instance->impl_->Shutdown();
109 }
110
111 // static
112 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
113 const std::vector<SerializedScriptValue>& values,
114 const string16& key_path,
115 std::vector<IndexedDBKey>* keys) {
116 IndexedDBKeyUtilityClient* instance = client_instance.Pointer();
117
118 if (instance->is_shutdown_) {
119 keys->clear();
120 return;
121 }
122
123 if (!instance->impl_) {
124 instance->impl_ = new KeyUtilityClientImpl();
125 instance->impl_->StartUtilityProcess();
126 }
127
128 instance->impl_->CreateIDBKeysFromSerializedValuesAndKeyPath(values, key_path,
129 keys);
130 }
131
132 // KeyUtilityClientImpl definitions.
133
134 void KeyUtilityClientImpl::Shutdown() {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136
137 utility_process_host_->EndBatchMode();
138 utility_process_host_ = NULL;
139 client_ = NULL;
140 state_ = STATE_SHUTDOWN;
141 }
142
143 KeyUtilityClientImpl::KeyUtilityClientImpl()
14 : waitable_event_(false, false), 144 : waitable_event_(false, false),
15 state_(STATE_UNINITIALIZED), 145 state_(STATE_UNINITIALIZED),
16 utility_process_host_(NULL) { 146 utility_process_host_(NULL) {
17 } 147 }
18 148
19 IndexedDBKeyUtilityClient::~IndexedDBKeyUtilityClient() { 149 KeyUtilityClientImpl::~KeyUtilityClientImpl() {
20 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN); 150 DCHECK(state_ == STATE_UNINITIALIZED || state_ == STATE_SHUTDOWN);
21 DCHECK(!utility_process_host_); 151 DCHECK(!utility_process_host_);
22 DCHECK(!client_.get()); 152 DCHECK(!client_.get());
23 } 153 }
24 154
25 void IndexedDBKeyUtilityClient::StartUtilityProcess() { 155 void KeyUtilityClientImpl::StartUtilityProcess() {
26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
27 DCHECK(state_ == STATE_UNINITIALIZED); 157 DCHECK(state_ == STATE_UNINITIALIZED);
28 158
29 GetRDHAndStartUtilityProcess(); 159 GetRDHAndStartUtilityProcess();
30 bool ret = waitable_event_.Wait(); 160 bool ret = waitable_event_.Wait();
31 161
32 DCHECK(ret && state_ == STATE_INITIALIZED); 162 DCHECK(ret && state_ == STATE_INITIALIZED);
33 } 163 }
34 164
35 void IndexedDBKeyUtilityClient::EndUtilityProcess() { 165 void KeyUtilityClientImpl::CreateIDBKeysFromSerializedValuesAndKeyPath(
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
37 DCHECK(state_ == STATE_INITIALIZED);
38
39 EndUtilityProcessInternal();
40 bool ret = waitable_event_.Wait();
41
42 DCHECK(ret && state_ == STATE_SHUTDOWN);
43 }
44
45 void IndexedDBKeyUtilityClient::CreateIDBKeysFromSerializedValuesAndKeyPath(
46 const std::vector<SerializedScriptValue>& values, 166 const std::vector<SerializedScriptValue>& values,
47 const string16& key_path, 167 const string16& key_path,
48 std::vector<IndexedDBKey>* keys) { 168 std::vector<IndexedDBKey>* keys) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT));
170 if (state_ == STATE_SHUTDOWN) {
171 keys->clear();
172 return;
173 }
174
50 DCHECK(state_ == STATE_INITIALIZED); 175 DCHECK(state_ == STATE_INITIALIZED);
51 176
52 state_ = STATE_CREATING_KEYS; 177 state_ = STATE_CREATING_KEYS;
53 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path); 178 CallStartIDBKeyFromValueAndKeyPathFromIOThread(values, key_path);
54 bool ret = waitable_event_.Wait(); 179 bool ret = waitable_event_.Wait();
55 DCHECK(ret && state_ == STATE_INITIALIZED); 180 DCHECK(ret && state_ == STATE_INITIALIZED);
56 181
57 *keys = keys_; 182 *keys = keys_;
58 } 183 }
59 184
60 void IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess() { 185 void KeyUtilityClientImpl::GetRDHAndStartUtilityProcess() {
61 // In order to start the UtilityProcess, we need to grab 186 // In order to start the UtilityProcess, we need to grab
62 // a pointer to the ResourceDispatcherHost. This can only 187 // a pointer to the ResourceDispatcherHost. This can only
63 // be done on the UI thread. See the comment at the top of 188 // be done on the UI thread. See the comment at the top of
64 // browser_process.h 189 // browser_process.h
65 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 190 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
66 BrowserThread::PostTask( 191 BrowserThread::PostTask(
67 BrowserThread::UI, FROM_HERE, 192 BrowserThread::UI, FROM_HERE,
68 NewRunnableMethod( 193 NewRunnableMethod(
69 this, 194 this,
70 &IndexedDBKeyUtilityClient::GetRDHAndStartUtilityProcess)); 195 &KeyUtilityClientImpl::GetRDHAndStartUtilityProcess));
71 return; 196 return;
72 } 197 }
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host()); 199 StartUtilityProcessInternal(g_browser_process->resource_dispatcher_host());
75 } 200 }
76 201
77 void IndexedDBKeyUtilityClient::StartUtilityProcessInternal( 202 void KeyUtilityClientImpl::StartUtilityProcessInternal(
78 ResourceDispatcherHost* rdh) { 203 ResourceDispatcherHost* rdh) {
79 DCHECK(rdh); 204 DCHECK(rdh);
80 // The ResourceDispatcherHost can only be used on the IO thread. 205 // The ResourceDispatcherHost can only be used on the IO thread.
81 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 206 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83 BrowserThread::PostTask( 208 BrowserThread::PostTask(
84 BrowserThread::IO, FROM_HERE, 209 BrowserThread::IO, FROM_HERE,
85 NewRunnableMethod( 210 NewRunnableMethod(
86 this, 211 this,
87 &IndexedDBKeyUtilityClient::StartUtilityProcessInternal, 212 &KeyUtilityClientImpl::StartUtilityProcessInternal,
88 rdh)); 213 rdh));
89 return; 214 return;
90 } 215 }
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
92 DCHECK(state_ == STATE_UNINITIALIZED); 217 DCHECK(state_ == STATE_UNINITIALIZED);
93 218
94 client_ = new IndexedDBKeyUtilityClient::Client(this); 219 client_ = new KeyUtilityClientImpl::Client(this);
95 utility_process_host_ = new UtilityProcessHost( 220 utility_process_host_ = new UtilityProcessHost(
96 rdh, client_.get(), BrowserThread::IO); 221 rdh, client_.get(), BrowserThread::IO);
97 utility_process_host_->StartBatchMode(); 222 utility_process_host_->StartBatchMode();
98 state_ = STATE_INITIALIZED; 223 state_ = STATE_INITIALIZED;
99 waitable_event_.Signal(); 224 waitable_event_.Signal();
100 } 225 }
101 226
102 void IndexedDBKeyUtilityClient::EndUtilityProcessInternal() { 227 void KeyUtilityClientImpl::EndUtilityProcessInternal() {
103 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 228 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
104 BrowserThread::PostTask( 229 BrowserThread::PostTask(
105 BrowserThread::IO, FROM_HERE, 230 BrowserThread::IO, FROM_HERE,
106 NewRunnableMethod( 231 NewRunnableMethod(
107 this, 232 this,
108 &IndexedDBKeyUtilityClient::EndUtilityProcessInternal)); 233 &KeyUtilityClientImpl::EndUtilityProcessInternal));
109 return; 234 return;
110 } 235 }
111 236
112 utility_process_host_->EndBatchMode(); 237 utility_process_host_->EndBatchMode();
113 utility_process_host_ = NULL; 238 utility_process_host_ = NULL;
114 client_ = NULL; 239 client_ = NULL;
115 state_ = STATE_SHUTDOWN; 240 state_ = STATE_SHUTDOWN;
116 waitable_event_.Signal(); 241 waitable_event_.Signal();
117 } 242 }
118 243
119 void IndexedDBKeyUtilityClient::CallStartIDBKeyFromValueAndKeyPathFromIOThread( 244 void KeyUtilityClientImpl::CallStartIDBKeyFromValueAndKeyPathFromIOThread(
120 const std::vector<SerializedScriptValue>& values, 245 const std::vector<SerializedScriptValue>& values,
121 const string16& key_path) { 246 const string16& key_path) {
122 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { 247 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
123 BrowserThread::PostTask( 248 BrowserThread::PostTask(
124 BrowserThread::IO, FROM_HERE, 249 BrowserThread::IO, FROM_HERE,
125 NewRunnableMethod(this, 250 NewRunnableMethod(this,
126 &IndexedDBKeyUtilityClient:: 251 &KeyUtilityClientImpl::
127 CallStartIDBKeyFromValueAndKeyPathFromIOThread, 252 CallStartIDBKeyFromValueAndKeyPathFromIOThread,
128 values, key_path)); 253 values, key_path));
129 return; 254 return;
130 } 255 }
131 256
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 257 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
133 utility_process_host_->StartIDBKeysFromValuesAndKeyPath( 258 utility_process_host_->StartIDBKeysFromValuesAndKeyPath(
134 0, values, key_path); 259 0, values, key_path);
135 } 260 }
136 261
137 void IndexedDBKeyUtilityClient::SetKeys(const std::vector<IndexedDBKey>& keys) { 262 void KeyUtilityClientImpl::SetKeys(const std::vector<IndexedDBKey>& keys) {
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
139 keys_ = keys; 264 keys_ = keys;
140 } 265 }
141 266
142 void IndexedDBKeyUtilityClient::FinishCreatingKeys() { 267 void KeyUtilityClientImpl::FinishCreatingKeys() {
143 DCHECK(state_ == STATE_CREATING_KEYS); 268 DCHECK(state_ == STATE_CREATING_KEYS);
144 state_ = STATE_INITIALIZED; 269 state_ = STATE_INITIALIZED;
145 waitable_event_.Signal(); 270 waitable_event_.Signal();
146 } 271 }
147 272
148 IndexedDBKeyUtilityClient::Client::Client(IndexedDBKeyUtilityClient* parent) 273 KeyUtilityClientImpl::Client::Client(KeyUtilityClientImpl* parent)
149 : parent_(parent) { 274 : parent_(parent) {
150 } 275 }
151 276
152 void IndexedDBKeyUtilityClient::Client::OnProcessCrashed(int exit_code) { 277 void KeyUtilityClientImpl::Client::OnProcessCrashed(int exit_code) {
153 if (parent_->state_ == STATE_CREATING_KEYS) 278 if (parent_->state_ == STATE_CREATING_KEYS)
154 parent_->FinishCreatingKeys(); 279 parent_->FinishCreatingKeys();
155 } 280 }
156 281
157 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathSucceeded( 282 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathSucceeded(
158 int id, const std::vector<IndexedDBKey>& keys) { 283 int id, const std::vector<IndexedDBKey>& keys) {
159 parent_->SetKeys(keys); 284 parent_->SetKeys(keys);
160 parent_->FinishCreatingKeys(); 285 parent_->FinishCreatingKeys();
161 } 286 }
162 287
163 void IndexedDBKeyUtilityClient::Client::OnIDBKeysFromValuesAndKeyPathFailed( 288 void KeyUtilityClientImpl::Client::OnIDBKeysFromValuesAndKeyPathFailed(
164 int id) { 289 int id) {
165 parent_->FinishCreatingKeys(); 290 parent_->FinishCreatingKeys();
166 } 291 }
OLDNEW
« no previous file with comments | « chrome/browser/in_process_webkit/indexed_db_key_utility_client.h ('k') | chrome/browser/io_thread.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698