Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |