While trying to dig around this morning I started adding clang-style thread locking annotations to the source code. These can be very handy and I found at least one place where the documented locking policy doesn't seem to match what is happening.
Here is an example with annotations, and what might or might not be a bug. With these annotations, clang will be able to prove whether the program obeys the locking regime or not.
But this is of course only one part of the RTS, but the locking can be pretty "interesting" in itself.
diff --git a/rts/Task.c b/rts/Task.c
index e6781a1..1e499dc 100644
--- a/rts/Task.c
+++ b/rts/Task.c
@@ -25,12 +25,12 @@
// Task lists and global counters.
// Locks required: all_tasks_mutex.
-Task *all_tasks = NULL;
+Task *all_tasks GUARDED_BY(all_tasks_mutex) = NULL;
-nat taskCount;
-nat workerCount;
-nat currentWorkerCount;
-nat peakWorkerCount;
+nat taskCount GUARDED_BY(all_tasks_mutex);
+nat workerCount GUARDED_BY(all_tasks_mutex);
+nat currentWorkerCount GUARDED_BY(all_tasks_mutex);
+nat peakWorkerCount GUARDED_BY(all_tasks_mutex);
static int tasksInitialized = 0;
@@ -339,9 +339,11 @@ void updateCapabilityRefs (void)
ACQUIRE_LOCK(&all_tasks_mutex);
for (task = all_tasks; task != NULL; task=task->all_next) {
+ ACQUIRE_LOCK(task->lock);
if (task->cap != NULL) {
task->cap = &capabilities[task->cap->no];
}
+ RELEASE_LOCK(task->lock);
for (incall = task->incall; incall != NULL; incall = incall->prev_stack) {
if (incall->suspended_cap != NULL) {