OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR **MemorySpaceMap\r
)\r
{\r
- EFI_STATUS Status;\r
LIST_ENTRY *Link;\r
EFI_GCD_MAP_ENTRY *Entry;\r
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor;\r
+ UINTN DescriptorCount;\r
\r
//\r
// Make sure parameters are valid\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- CoreAcquireGcdMemoryLock ();\r
+ *NumberOfDescriptors = 0;\r
+ *MemorySpaceMap = NULL;\r
\r
//\r
- // Count the number of descriptors\r
+ // Take the lock, for entering the loop with the lock held.\r
//\r
- *NumberOfDescriptors = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);\r
+ CoreAcquireGcdMemoryLock ();\r
+ while (TRUE) {\r
+ //\r
+ // Count descriptors. It might be done more than once because the\r
+ // AllocatePool() called below has to be running outside the GCD lock.\r
+ //\r
+ DescriptorCount = CoreCountGcdMapEntry (&mGcdMemorySpaceMap);\r
+ if (DescriptorCount == *NumberOfDescriptors) {\r
+ //\r
+ // Fill in the MemorySpaceMap if no memory space map change.\r
+ //\r
+ Descriptor = *MemorySpaceMap;\r
+ Link = mGcdMemorySpaceMap.ForwardLink;\r
+ while (Link != &mGcdMemorySpaceMap) {\r
+ Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
+ BuildMemoryDescriptor (Descriptor, Entry);\r
+ Descriptor++;\r
+ Link = Link->ForwardLink;\r
+ }\r
+ //\r
+ // We're done; exit the loop with the lock held.\r
+ //\r
+ break;\r
+ }\r
\r
- //\r
- // Allocate the MemorySpaceMap\r
- //\r
- *MemorySpaceMap = AllocatePool (*NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
- if (*MemorySpaceMap == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Done;\r
- }\r
+ //\r
+ // Release the lock before memory allocation, because it might cause\r
+ // GCD lock conflict in one of calling path in AllocatPool().\r
+ //\r
+ CoreReleaseGcdMemoryLock ();\r
+\r
+ //\r
+ // Allocate memory to store the MemorySpaceMap. Note it might be already\r
+ // allocated if there's map descriptor change during memory allocation at\r
+ // last time.\r
+ //\r
+ if (*MemorySpaceMap != NULL) {\r
+ FreePool (*MemorySpaceMap);\r
+ }\r
\r
+ *MemorySpaceMap = AllocatePool (DescriptorCount *\r
+ sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));\r
+ if (*MemorySpaceMap == NULL) {\r
+ *NumberOfDescriptors = 0;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Save the descriptor count got before for another round of check to make\r
+ // sure we won't miss any, since we have code running outside the GCD lock.\r
+ //\r
+ *NumberOfDescriptors = DescriptorCount;\r
+ //\r
+ // Re-acquire the lock, for the next iteration.\r
+ //\r
+ CoreAcquireGcdMemoryLock ();\r
+ }\r
//\r
- // Fill in the MemorySpaceMap\r
+ // We exited the loop with the lock held, release it.\r
//\r
- Descriptor = *MemorySpaceMap;\r
- Link = mGcdMemorySpaceMap.ForwardLink;\r
- while (Link != &mGcdMemorySpaceMap) {\r
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);\r
- BuildMemoryDescriptor (Descriptor, Entry);\r
- Descriptor++;\r
- Link = Link->ForwardLink;\r
- }\r
- Status = EFI_SUCCESS;\r
-\r
-Done:\r
CoreReleaseGcdMemoryLock ();\r
- return Status;\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
\r