From 0146fbe3ceab96759f1e55e73daaa6d6d7bc4b9b Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sat, 12 Apr 2008 04:14:25 +0000
Subject: use the pthread API in notify.c

This patch rewrites notify.c to use the pthread API, namely
pthread_mutex and pthread_cond.  This is a lot cheaper and easier than
the pipe() hack.

git-svn-id: https://svn.musicpd.org/mpd/trunk@7280 09075e82-0dd4-0310-85a5-a0d7c8717e4f
---
 src/notify.c | 54 +++++++++++++++++++++++++++++++++++++-----------------
 src/notify.h | 45 +++++++++++++++++++++++++++++----------------
 2 files changed, 66 insertions(+), 33 deletions(-)

diff --git a/src/notify.c b/src/notify.c
index 4eda79391..5d53b231d 100644
--- a/src/notify.c
+++ b/src/notify.c
@@ -17,32 +17,52 @@
  */
 
 #include "notify.h"
-#include "os_compat.h"
-#include "log.h"
-#include "utils.h"
 
-void notifyInit(Notify *notify)
+int notifyInit(Notify *notify)
 {
-	if (pipe(notify->fds) < 0)
-		FATAL("Couldn't open pipe: %s", strerror(errno));
-	if (set_nonblocking(notify->fds[1]) < 0)
-		FATAL("Couldn't set non-blocking on notify fd: %s",
-		      strerror(errno));
+	int ret;
+
+	ret = pthread_mutex_init(&notify->mutex, NULL);
+	if (ret != 0)
+		return ret;
+
+	ret = pthread_cond_init(&notify->cond, NULL);
+	if (ret != 0) {
+		pthread_mutex_destroy(&notify->mutex);
+		return ret;
+	}
+
+	notify->pending = 0;
+
+	return 0;
 }
 
-void notifyWait(Notify *notify)
+void notifyEnter(Notify *notify)
 {
-	char buffer[64];
+	pthread_mutex_lock(&notify->mutex);
+}
 
-	if (read(notify->fds[0], buffer, sizeof(buffer)) < 0)
-		FATAL("error reading from pipe: %s\n", strerror(errno));
+void notifyLeave(Notify *notify)
+{
+	pthread_mutex_unlock(&notify->mutex);
+}
+
+void notifyWait(Notify *notify)
+{
+	if (!notify->pending)
+		pthread_cond_wait(&notify->cond, &notify->mutex);
+	notify->pending = 0;
 }
 
 void notifySignal(Notify *notify)
 {
-	char buffer = 0;
+	notify->pending = 1;
+	pthread_cond_signal(&notify->cond);
+}
 
-	if (write(notify->fds[1], &buffer, sizeof(buffer)) < 0 &&
-	    errno != EAGAIN && errno != EINTR)
-		FATAL("error writing to pipe: %s\n", strerror(errno));
+void notifySignalSync(Notify *notify)
+{
+	pthread_mutex_lock(&notify->mutex);
+	notifySignal(notify);
+	pthread_mutex_unlock(&notify->mutex);
 }
diff --git a/src/notify.h b/src/notify.h
index 9f1a1961b..f79518f8f 100644
--- a/src/notify.h
+++ b/src/notify.h
@@ -19,29 +19,42 @@
 #ifndef NOTIFY_H
 #define NOTIFY_H
 
-/*
- * This library implements inter-process signalling using blocking
- * read() on an anonymous pipe.  As a side effect, the read() system
- * call has the same signal interruption behaviour as the old sleep
- * function.
- *
- * As soon as mpd uses threading instead of fork()/shm, we can replace
- * this library with a pthread_cond object.
- *
- * This code is experimental and carries a lot of overhead.  Still, it
- * uses less resources than the old polling code with a fixed sleep
- * time.
- *
- */
+#include "os_compat.h"
 
 typedef struct _Notify {
-	int fds[2];
+	pthread_mutex_t mutex;
+	pthread_cond_t cond;
+	int pending;
 } Notify;
 
-void notifyInit(Notify *notify);
+int notifyInit(Notify *notify);
+
+/**
+ * The thread which shall be notified by this object must call this
+ * function before any notifyWait() invocation.  It locks the mutex.
+ */
+void notifyEnter(Notify *notify);
+
+/**
+ * Neutralize notifyLeave().
+ */
+void notifyLeave(Notify *notify);
 
+/**
+ * Wait for a notification.  Return immediately if we have already
+ * been notified since we last returned from notifyWait().
+ */
 void notifyWait(Notify *notify);
 
+/**
+ * Notify the thread.  This function never blocks.
+ */
 void notifySignal(Notify *notify);
 
+/**
+ * Notify the thread synchonously, i.e. wait until it has received the
+ * notification.
+ */
+void notifySignalSync(Notify *notify);
+
 #endif
-- 
cgit v1.2.3