git » nmdb » commit d91eb55

Add sparse annotations for queue lock checking

author Alberto Bertogli
2007-04-01 04:47:08 UTC
committer Alberto Bertogli
2008-06-24 06:10:04 UTC
parent 4d3dba5bd6b624572d880ffa54fea565e1e046f2

Add sparse annotations for queue lock checking

Signed-off-by: Alberto Bertogli <albertito@gmail.com>

nmdb/dbloop.c +4 -0
nmdb/queue.c +7 -0
nmdb/queue.h +14 -7
nmdb/sparse.h +21 -0

diff --git a/nmdb/dbloop.c b/nmdb/dbloop.c
index 0a7e4a7..bb20504 100644
--- a/nmdb/dbloop.c
+++ b/nmdb/dbloop.c
@@ -14,6 +14,7 @@
 #include "req.h"
 #include "log.h"
 #include "netutils.h"
+#include "sparse.h"
 
 
 static void *db_loop(void *arg);
@@ -74,6 +75,9 @@ static void *db_loop(void *arg)
 
 		if (rv != 0 && rv != ETIMEDOUT) {
 			errlog("Error in queue_timedwait()");
+			/* When the timedwait fails the lock is released, so
+			 * we need to properly annotate this case. */
+			__release(op_queue->lock);
 			continue;
 		}
 
diff --git a/nmdb/queue.c b/nmdb/queue.c
index eb56b09..0629f82 100644
--- a/nmdb/queue.c
+++ b/nmdb/queue.c
@@ -32,11 +32,18 @@ void queue_free(struct queue *q)
 {
 	struct queue_entry *e;
 
+	/* We know when we're called there is no other possible queue user;
+	 * however, we don't have any sane way to tell sparse about this, so
+	 * fake the acquisition of the lock to comply with the operations
+	 * performed inside. Obviously, it would be completely safe to do the
+	 * queue_lock()/unlock(), but it'd be misleading to the reader */
+	__acquire(q->lock);
 	e = queue_get(q);
 	while (e != NULL) {
 		queue_entry_free(e);
 		e = queue_get(q);
 	}
+	__release(q->lock);
 
 	pthread_mutex_destroy(&(q->lock));
 
diff --git a/nmdb/queue.h b/nmdb/queue.h
index f50abe5..17a4ec0 100644
--- a/nmdb/queue.h
+++ b/nmdb/queue.h
@@ -5,6 +5,7 @@
 #include <pthread.h>		/* for mutexes */
 #include <stdint.h>		/* for uint32_t */
 #include "req.h"		/* for req_info */
+#include "sparse.h"
 
 struct queue {
 	pthread_mutex_t lock;
@@ -38,14 +39,20 @@ void queue_free(struct queue *q);
 struct queue_entry *queue_entry_create();
 void queue_entry_free(struct queue_entry *e);
 
-void queue_lock(struct queue *q);
-void queue_unlock(struct queue *q);
+void queue_lock(struct queue *q)
+	__acquires(q->lock);
+void queue_unlock(struct queue *q)
+	__releases(q->lock);
 void queue_signal(struct queue *q);
-int queue_timedwait(struct queue *q, struct timespec *ts);
-
-void queue_put(struct queue *q, struct queue_entry *e);
-struct queue_entry *queue_get(struct queue *q);
-int queue_isempty(struct queue *q);
+int queue_timedwait(struct queue *q, struct timespec *ts)
+	__with_lock_acquired(q->lock);
+
+void queue_put(struct queue *q, struct queue_entry *e)
+	__with_lock_acquired(q->lock);
+struct queue_entry *queue_get(struct queue *q)
+	__with_lock_acquired(q->lock);
+int queue_isempty(struct queue *q)
+	__with_lock_acquired(q->lock);
 
 #endif
 
diff --git a/nmdb/sparse.h b/nmdb/sparse.h
new file mode 100644
index 0000000..20adafc
--- /dev/null
+++ b/nmdb/sparse.h
@@ -0,0 +1,21 @@
+
+/* Useful defines to use with sparse */
+
+#ifndef _SPARSE_H
+#define _SPARSE_H
+
+#ifdef __CHECKER__
+# define __acquires(x) __attribute__((exact_context(x,0,1)))
+# define __releases(x) __attribute__((exact_context(x,1,0)))
+# define __with_lock_acquired(x) __attribute__((exact_context(x,1,1)))
+# define __acquire(x) __context__(x,1,0)
+# define __release(x) __context__(x,-1,1)
+#else
+# define __acquires(x)
+# define __releases(x)
+# define __with_lock_acquired(x)
+# define __acquire(x) (void)0
+# define __release(x) (void)0
+#endif
+
+#endif