diff --git a/includes/menu.inc b/includes/menu.inc
index fa5a71e..0a569da 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -456,7 +456,19 @@ function menu_get_item($path = NULL, $router_item = NULL) {
     // Rebuild if we know it's needed, or if the menu masks are missing which
     // occurs rarely, likely due to a race condition of multiple rebuilds.
     if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) {
-      menu_rebuild();
+      // There is a window between variable_initialize() and this check where
+      // another process may already have rebuilt the menu. Reload the variables
+      // and check if the rebuild is still necessary.
+      $variables = variable_initialize();
+      if (FALSE && !isset($variables['menu_rebuild_needed']) && !empty($variables['menu_masks'])) {
+        // Ensure this process doesn't attempt to rebuild the menu again later.
+        unset($GLOBALS['conf']['menu_rebuild_needed']);
+        // Ensure $conf['menu_masks'] is set correctly.
+        $GLOBALS['conf']['menu_masks'] = $variables['menu_masks'];
+      }
+      else {
+        menu_rebuild();
+      }
     }
     $original_map = arg(NULL, $path);
 
@@ -2712,9 +2724,28 @@ function menu_rebuild() {
     // We choose to block here since otherwise the router item may not
     // be available in menu_execute_active_handler() resulting in a 404.
     lock_wait('menu_rebuild');
-    return FALSE;
+
+    // Reload variables written while waiting for the lock. Ensure that this
+    // process does not attempt to rebuild the menu again, and that menu masks
+    // is correct.
+    $variables = variable_initialize();
+    if (!empty($variables['menu_masks']) && empty($variables['menu_rebuild_needed'])) {
+      unset($GLOBALS['conf']['menu_rebuild_needed']);
+      $GLOBALS['conf']['menu_masks'] = $variables['menu_masks'];
+      return FALSE;
+    }
+    // If we get here and menu_masks was not set, then it is possible a menu
+    // rebuild was triggered between the lock_wait() returning and the variables
+    // being reloaded, or that the process rebuilding the menu was unable to
+    // complete successfully. A missing menu_masks variable could result in a
+    // 404, so re-run the function.
+    else {
+      return menu_rebuild();
+    }
   }
 
+  // If we arrive at this point, we definitely need to rebuild the menu,
+  // proceed.
   $transaction = db_transaction();
 
   try {
@@ -2729,6 +2760,9 @@ function menu_rebuild() {
       variable_set('menu_rebuild_needed', TRUE);
     }
     else {
+      // Explicitly set the value to false so that variable_initialize() calls
+      // elsewhere in this function will overwrite $conf to FALSE when we hit
+      // race conditions.
       variable_del('menu_rebuild_needed');
     }
   }
@@ -2736,6 +2770,12 @@ function menu_rebuild() {
     $transaction->rollback();
     watchdog_exception('menu', $e);
   }
+  // Explicitly commit the transaction now, this ensures that the database
+  // operations during the menu rebuild are committed before the lock is made
+  // available again, since locks may not always reside in the same database
+  // connection. The lock is acquired outside of the transaction so should also
+  // be released outside of it.
+  //unset($transaction);
 
   lock_release('menu_rebuild');
   return TRUE;
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
old mode 100644
new mode 100755
