Add a `eventgroup_destroy_force` API.

This new API destroys an event group without tacking the lock.

This API is inherently racy. Its main purpose is to cleanup the event
group in an error handler context, when taking lock may be impossible.

While we are at it, all `eventgroup_destroy` operations, forced or not,
should upgrade the lock for destruction before freeing it.

Signed-off-by: Hugo Lefeuvre <hugo.lefeuvre@scisemi.com>
diff --git a/sdk/include/event.h b/sdk/include/event.h
index 2c24484..0fa3d41 100644
--- a/sdk/include/event.h
+++ b/sdk/include/event.h
@@ -108,3 +108,12 @@
  */
 int __cheri_libcall eventgroup_destroy(struct SObjStruct *heapCapability,
                                        struct EventGroup *group);
+
+/**
+ * Destroy an event group without tacking the lock.
+ *
+ * This API is inherently racy. Its main purpose is to cleanup the event group
+ * in an error handler context, when taking lock may be impossible.
+ */
+int __cheri_libcall eventgroup_destroy_force(struct SObjStruct *heapCapability,
+                                             struct EventGroup *group);
diff --git a/sdk/lib/event_group/event_group.cc b/sdk/lib/event_group/event_group.cc
index ef28ba8..dafa1eb 100644
--- a/sdk/lib/event_group/event_group.cc
+++ b/sdk/lib/event_group/event_group.cc
@@ -177,9 +177,9 @@
 	return 0;
 }
 
-int eventgroup_destroy(SObjStruct *heapCapability, EventGroup *group)
+int eventgroup_destroy_force(SObjStruct *heapCapability, EventGroup *group)
 {
-	group->lock.lock();
+	group->lock.upgrade_for_destruction();
 	// Force all waiters to wake.
 	for (size_t i = 0; i < group->waiterCount; ++i)
 	{
@@ -193,3 +193,9 @@
 	heap_free(heapCapability, group);
 	return 0;
 }
+
+int eventgroup_destroy(SObjStruct *heapCapability, EventGroup *group)
+{
+	group->lock.lock();
+	return eventgroup_destroy_force(heapCapability, group);
+}