diff --git a/core/lib/Drupal/Core/Lock/LockBackendAbstract.php b/core/lib/Drupal/Core/Lock/LockBackendAbstract.php index 41ee27cab4..32e5ab4c6a 100644 --- a/core/lib/Drupal/Core/Lock/LockBackendAbstract.php +++ b/core/lib/Drupal/Core/Lock/LockBackendAbstract.php @@ -37,18 +37,30 @@ public function wait($name, $delay = 30) { // time until it reaches 500ms. After this point polling will continue every // 500ms until $delay is reached. + // If executing inside a fiber, then suspending the fiber implicitly waits + // for whatever the parent process does before it is resumed again. Try + // that so that other tasks can continue, before sleeping only if necessary. + if (\Fiber::getCurrent() !== NULL) { + $sleep = 0; + \Fiber::suspend(); + } + else { + // Begin sleeping at 25ms. + $sleep = 25000; + } + // $delay is passed in seconds, but we will be using usleep(), which takes // microseconds as a parameter. Multiply it by 1 million so that all // further numbers are equivalent. $delay = (int) $delay * 1000000; - // Begin sleeping at 25ms. - $sleep = 25000; while ($delay > 0) { // This function should only be called by a request that failed to get a - // lock, so we sleep first to give the parallel request a chance to finish - // and release the lock. - usleep($sleep); + // lock, so if we haven't already suspended a fiber, sleep first to give + // the parallel request a chance to finish and release the lock. + if ($sleep > 0) { + usleep($sleep); + } // After each sleep, increase the value of $sleep until it reaches // 500ms, to reduce the potential for a lock stampede. $delay = $delay - $sleep; diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php index f0e6118a39..adf1cde7d8 100644 --- a/core/lib/Drupal/Core/Theme/Registry.php +++ b/core/lib/Drupal/Core/Theme/Registry.php @@ -237,13 +237,19 @@ protected function init($theme_name = NULL) { */ public function get() { $this->init($this->themeName); - if (isset($this->registry[$this->theme->getName()])) { - return $this->registry[$this->theme->getName()]; - } - if ($cache = $this->cache->get('theme_registry:' . $this->theme->getName())) { - $this->registry[$this->theme->getName()] = $cache->data; - } - else { + if (!$this->cacheGet()) { + // If called from inside a fiber, suspend it, this may allow another code + // path to begin an asynchronous operation before we do the CPU-intensive + // task of building the theme registry. + if (\Fiber::getCurrent() !== NULL) { + \Fiber::suspend(); + // When we return from the fiber being suspended, check the cache again + // since it may have been built in the meantime, either in this process + // or via a different request altogether. + if ($this->cacheGet()) { + return $this->registry[$this->theme->getName()]; + } + } $this->build(); // Only persist it if all modules are loaded to ensure it is complete. if ($this->moduleHandler->isLoaded()) { @@ -253,6 +259,16 @@ public function get() { return $this->registry[$this->theme->getName()]; } + /** + * Gets the theme registry cache. + */ + protected function cacheGet(): void { + $theme_name = $this->theme->getName(); + if (!isset($this->registry[$theme_name]) && $cache = $this->cache->get('theme_registry:' . $theme_name)) { + $this->registry[$theme_name] = $cache->data; + } + } + /** * Returns the incomplete, runtime theme registry. *