Differentiate heap/quota exhausted in the return value of `mspace_dispatch`.

The return value of `mspace_dispatch` currently maps two error types,
1) heap exhausted and 2) quota exhausted, to the same return error tag
type `AllocationFailureDeallocationNeeded`.

Since we need to distinguish between the two in `heap_allocate*`,
create two new distinct tag types.

While at it, clarify the documentation of `mspace_dispatch`.

Signed-off-by: Hugo Lefeuvre <hugo.lefeuvre@scisemi.com>
diff --git a/sdk/core/allocator/alloc.h b/sdk/core/allocator/alloc.h
index 9d63a74..20ba2da 100644
--- a/sdk/core/allocator/alloc.h
+++ b/sdk/core/allocator/alloc.h
@@ -1099,9 +1099,17 @@
 
 	/**
 	 * Tag type indicating that the requested allocation cannot succeed until
+	 * some objects have been freed in the passed quota.
+	 */
+	struct AllocationFailureQuotaExceeded
+	{
+	};
+
+	/**
+	 * Tag type indicating that the requested allocation cannot succeed until
 	 * some objects have been freed.
 	 */
-	struct AllocationFailureDeallocationNeeded
+	struct AllocationFailureHeapFull
 	{
 	};
 
@@ -1110,7 +1118,8 @@
 	 */
 	using AllocationResult = std::variant<AllocationFailurePermanent,
 	                                      AllocationFailureRevocationNeeded,
-	                                      AllocationFailureDeallocationNeeded,
+	                                      AllocationFailureQuotaExceeded,
+	                                      AllocationFailureHeapFull,
 	                                      CHERI::Capability<void>>;
 
 	/**
@@ -1126,7 +1135,8 @@
 	 * object.  This allows it to be skipped when freeing all objects allocated
 	 * with a given quota.
 	 *
-	 * @return User pointer if request can be satisfied, nullptr otherwise.
+	 * @return User pointer if request can be satisfied, or a tag type
+	 * representing the error otherwise.
 	 */
 	AllocationResult mspace_dispatch(size_t   bytes,
 	                                 size_t  &quota,
@@ -1161,7 +1171,7 @@
 			           "quota is {})",
 			           alignSize,
 			           quota);
-			return AllocationFailureDeallocationNeeded{};
+			return AllocationFailureQuotaExceeded{};
 		}
 		CHERI::Capability<void> ret{mspace_memalign(
 		  alignSize, -CHERI::representable_alignment_mask(bytes))};
@@ -1180,7 +1190,7 @@
 			{
 				return AllocationFailurePermanent{};
 			}
-			return AllocationFailureDeallocationNeeded{};
+			return AllocationFailureHeapFull{};
 		}
 		auto header = MChunkHeader::from_body(ret);
 
@@ -1194,7 +1204,7 @@
 			           header->size_get(),
 			           quota);
 			mspace_free_internal(header);
-			return AllocationFailureDeallocationNeeded{};
+			return AllocationFailureQuotaExceeded{};
 		}
 
 		if constexpr (DEBUG_ALLOCATOR)
diff --git a/sdk/core/allocator/main.cc b/sdk/core/allocator/main.cc
index 7a47e82..bb8160c 100644
--- a/sdk/core/allocator/main.cc
+++ b/sdk/core/allocator/main.cc
@@ -303,8 +303,10 @@
 			}
 			// If the heap is full, wait for someone to free an allocation and
 			// then retry.
-			if (std::holds_alternative<
-			      MState::AllocationFailureDeallocationNeeded>(ret))
+			if (std::holds_alternative<MState::AllocationFailureHeapFull>(
+			      ret) ||
+			    std::holds_alternative<MState::AllocationFailureQuotaExceeded>(
+			      ret))
 			{
 				Debug::log("Not enough free space to handle {}-byte "
 				           "allocation, sleeping",