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

Side by Side Diff: tools/gn/input_file_manager.cc

Issue 645253002: GN: Store parse error messages (so they aren't dropped due to races) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 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
« tools/gn/input_file_manager.h ('K') | « tools/gn/input_file_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) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "tools/gn/input_file_manager.h" 5 #include "tools/gn/input_file_manager.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "tools/gn/filesystem_utils.h" 9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/parser.h" 10 #include "tools/gn/parser.h"
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 { 208 {
209 base::AutoUnlock unlock(lock_); 209 base::AutoUnlock unlock(lock_);
210 data->completion_event->Wait(); 210 data->completion_event->Wait();
211 } 211 }
212 // If there were multiple waiters on the same event, we now need to wake 212 // If there were multiple waiters on the same event, we now need to wake
213 // up the next one. 213 // up the next one.
214 data->completion_event->Signal(); 214 data->completion_event->Signal();
215 } 215 }
216 } 216 }
217 217
218 // The other load could have failed. In this case that error was probably 218 // The other load could have failed. It is possible that this thread's error
219 // printed to the console, but we need to return something here, so make up a 219 // will be reported to the scheduler before the other thread's (and the first
220 // dummy error. 220 // error reported "wins"). Forward the parse error from the other load for
221 // 221 // this thread so that the error message is useful.
222 // There is a race condition. The other load could have failed, but if the
223 // other thread is delayed for some reason, this thread could end up
224 // reporting the error to the scheduler first (since first error report
225 // wins). The user will see this one and the "real" one will be discarded.
226 if (!data->parsed_root) { 222 if (!data->parsed_root) {
brettw 2014/10/14 17:13:09 Remove {}
cjhopman 2014/10/16 18:26:02 Done.
227 *err = Err(origin, "File parse failed.", 223 *err = *data->parse_error;
228 "If you see this, I'm really sorry, but a race condition has caused\n"
229 "me to eat your error message. It was crunchy. If the parse error\n"
230 "in your imported file isn't obvious, try re-running GN.");
231 } 224 }
232 return data->parsed_root.get(); 225 return data->parsed_root.get();
233 } 226 }
234 227
235 void InputFileManager::AddDynamicInput(const SourceFile& name, 228 void InputFileManager::AddDynamicInput(const SourceFile& name,
236 InputFile** file, 229 InputFile** file,
237 std::vector<Token>** tokens, 230 std::vector<Token>** tokens,
238 scoped_ptr<ParseNode>** parse_root) { 231 scoped_ptr<ParseNode>** parse_root) {
239 InputFileData* data = new InputFileData(name); 232 InputFileData* data = new InputFileData(name);
240 { 233 {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 std::vector<FileLoadCallback> callbacks; 282 std::vector<FileLoadCallback> callbacks;
290 { 283 {
291 base::AutoLock lock(lock_); 284 base::AutoLock lock(lock_);
292 DCHECK(input_files_.find(name) != input_files_.end()); 285 DCHECK(input_files_.find(name) != input_files_.end());
293 286
294 InputFileData* data = input_files_[name]; 287 InputFileData* data = input_files_[name];
295 data->loaded = true; 288 data->loaded = true;
296 if (success) { 289 if (success) {
297 data->tokens.swap(tokens); 290 data->tokens.swap(tokens);
298 data->parsed_root = root.Pass(); 291 data->parsed_root = root.Pass();
292 } else {
293 data->parse_error.reset(new Err(*err));
299 } 294 }
300 295
301 // Unblock waiters on this event. 296 // Unblock waiters on this event.
302 // 297 //
303 // It's somewhat bad to signal this inside the lock. When it's used, it's 298 // It's somewhat bad to signal this inside the lock. When it's used, it's
304 // lazily created inside the lock. So we need to do the check and signal 299 // lazily created inside the lock. So we need to do the check and signal
305 // inside the lock to avoid race conditions on the lazy creation of the 300 // inside the lock to avoid race conditions on the lazy creation of the
306 // lock. 301 // lock.
307 // 302 //
308 // We could avoid this by creating the lock every time, but the lock is 303 // We could avoid this by creating the lock every time, but the lock is
309 // very seldom used and will generally be NULL, so my current theory is that 304 // very seldom used and will generally be NULL, so my current theory is that
310 // several signals of a completion event inside a lock is better than 305 // several signals of a completion event inside a lock is better than
311 // creating about 1000 extra locks (one for each file). 306 // creating about 1000 extra locks (one for each file).
312 if (data->completion_event) 307 if (data->completion_event)
313 data->completion_event->Signal(); 308 data->completion_event->Signal();
314 309
315 callbacks.swap(data->scheduled_callbacks); 310 callbacks.swap(data->scheduled_callbacks);
316 } 311 }
317 312
318 // Run pending invocations. Theoretically we could schedule each of these 313 // Run pending invocations. Theoretically we could schedule each of these
319 // separately to get some parallelism. But normally there will only be one 314 // separately to get some parallelism. But normally there will only be one
320 // item in the list, so that's extra overhead and complexity for no gain. 315 // item in the list, so that's extra overhead and complexity for no gain.
321 if (success) { 316 if (success) {
322 for (const auto& cb : callbacks) 317 for (const auto& cb : callbacks)
323 cb.Run(unowned_root); 318 cb.Run(unowned_root);
324 } 319 }
325 return success; 320 return success;
326 } 321 }
OLDNEW
« tools/gn/input_file_manager.h ('K') | « tools/gn/input_file_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698