| 402 | } |
| 403 | |
| 404 | void GameEventHandler::OnBeginFrame() |
| 405 | { |
| 406 | if (!_pendingCallbacks.empty()) { |
| 407 | ZoneScopedNC("Pending callbacks", 0x888888); |
| 408 | |
| 409 | std::weak_ptr<void> emptyRef; |
| 410 | Function<void()> callbackFunc; |
| 411 | std::size_t i = 0; |
| 412 | |
| 413 | while (true) { |
| 414 | { |
| 415 | #if defined(WITH_THREADS) |
| 416 | std::unique_lock<std::mutex> lock(_pendingCallbacksLock); |
| 417 | #endif |
| 418 | if (i >= _pendingCallbacks.size()) { |
| 419 | break; |
| 420 | } |
| 421 | |
| 422 | auto& callback = _pendingCallbacks[i]; |
| 423 | auto& callbackRef = callback.first(); |
| 424 | // Invoke the callback only if it has no corresponding reference or the reference is still alive |
| 425 | if (!callbackRef.expired() || !(callbackRef.owner_before(emptyRef) || emptyRef.owner_before(callbackRef))) { |
| 426 | // Callback cannot be invoked under the lock, because it can invoke another callback and it would cause deadlock |
| 427 | callbackFunc = std::move(callback.second()); |
| 428 | } else { |
| 429 | LOGW("Deferred callback dropped due to dead reference"); |
| 430 | i++; |
| 431 | continue; |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | callbackFunc(); |
| 436 | i++; |
| 437 | } |
| 438 | |
| 439 | _pendingCallbacks.clear(); |
| 440 | } |
| 441 | |
| 442 | _currentHandler->OnBeginFrame(); |
| 443 | } |
| 444 | |
| 445 | void GameEventHandler::OnPostUpdate() |
| 446 | { |