diff --git a/glib/ghash.c b/glib/ghash.c
index 492aa20..873ae77 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -460,57 +460,91 @@ g_hash_table_remove_node (GHashTable   *hash_table,
  * If @notify is %TRUE then the destroy notify functions are called
  * for the key and value of the hash node.
  */
 static void
 g_hash_table_remove_all_nodes (GHashTable *hash_table,
                                gboolean    notify)
 {
   int i;
   gpointer key;
   gpointer value;
+  gint old_size;
+  gpointer *old_keys;
+  gpointer *old_values;
+  guint    *old_hashes;
 
   hash_table->nnodes = 0;
   hash_table->noccupied = 0;
 
   if (!notify ||
       (hash_table->key_destroy_func == NULL &&
        hash_table->value_destroy_func == NULL))
     {
       memset (hash_table->hashes, 0, hash_table->size * sizeof (guint));
       memset (hash_table->keys, 0, hash_table->size * sizeof (gpointer));
       memset (hash_table->values, 0, hash_table->size * sizeof (gpointer));
 
       return;
     }
 
-  for (i = 0; i < hash_table->size; i++)
+  old_size = hash_table->size;
+  old_keys = hash_table->keys;
+  old_values = hash_table->values;
+  old_hashes = hash_table->hashes;
+
+  g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
+  hash_table->keys               = g_new0 (gpointer, hash_table->size);
+  if (old_keys == old_values)
+    hash_table->values           = hash_table->keys;
+  else
+    hash_table->values           = g_new0 (gpointer, hash_table->size);
+    
+  hash_table->hashes             = g_new0 (guint, hash_table->size);
+
+  /* Erect tombstone for every node that is going to be deleted.
+   * For all other ones, set to unused.
+   * This way we prevent any operations that might happen on other entries
+   * from destroy notifiers. */
+  for (i = 0; i < old_size; i++)
     {
-      if (HASH_IS_REAL (hash_table->hashes[i]))
+      if (HASH_IS_REAL (old_hashes[i]))
+        old_hashes[i] = TOMBSTONE_HASH_VALUE;
+      else
+        old_hashes[i] = UNUSED_HASH_VALUE;
+    }
+
+  /* Now destroy all values. */
+  for (i = 0; i < old_size; i++)
+    {
+      if (HASH_IS_TOMBSTONE (old_hashes[i]))
         {
-          key = hash_table->keys[i];
-          value = hash_table->values[i];
+          key = old_keys[i];
+          value = old_values[i];
 
-          hash_table->hashes[i] = UNUSED_HASH_VALUE;
-          hash_table->keys[i] = NULL;
-          hash_table->values[i] = NULL;
+          old_hashes[i] = UNUSED_HASH_VALUE;
+          old_keys[i] = NULL;
+          old_values[i] = NULL;
 
           if (hash_table->key_destroy_func != NULL)
             hash_table->key_destroy_func (key);
 
           if (hash_table->value_destroy_func != NULL)
             hash_table->value_destroy_func (value);
         }
-      else if (HASH_IS_TOMBSTONE (hash_table->hashes[i]))
-        {
-          hash_table->hashes[i] = UNUSED_HASH_VALUE;
-        }
     }
+
+  /* Destroy old storage space. */
+  if (old_keys != old_values)
+    g_free (old_values);
+
+  g_free (old_keys);
+  g_free (old_hashes);
 }
 
 /*
  * g_hash_table_resize:
  * @hash_table: our #GHashTable
  *
  * Resizes the hash table to the optimal size based on the number of
  * nodes currently held. If you call this function then a resize will
  * occur, even if one does not need to occur.
  * Use g_hash_table_maybe_resize() instead.
