[glib/wip/linux: 5/6] Add mutex implementation variant for Linux



commit bd97509f3da9ebac128a6265ead51de1e1034b37
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Sep 30 17:08:50 2011 -0400

    Add mutex implementation variant for Linux

 glib/Makefile.am    |    2 +-
 glib/gmutex-futex.c |  324 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 325 insertions(+), 1 deletions(-)
---
diff --git a/glib/Makefile.am b/glib/Makefile.am
index b863db5..519e6d8 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -221,7 +221,7 @@ endif
 if OS_WIN32
 libglib_2_0_la_SOURCES += gthread-win32.c
 else
-libglib_2_0_la_SOURCES += gthread-posix.c gmutex-posix.c
+libglib_2_0_la_SOURCES += gthread-posix.c gmutex-futex.c
 endif
 
 EXTRA_libglib_2_0_la_SOURCES = \
diff --git a/glib/gmutex-futex.c b/glib/gmutex-futex.c
new file mode 100644
index 0000000..5f5a96c
--- /dev/null
+++ b/glib/gmutex-futex.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright  2011 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "config.h"
+
+#include "gmutex.h"
+
+#include "gatomic.h"
+
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+
+/* Next to gatomic, this file is one of the lowest-level parts of GLib.
+ * All other parts of GLib (messages, memory, slices, etc) assume that
+ * they can freely use these facilities without risking recursion.
+ *
+ * As such, these functions are NOT permitted to call any other part of
+ * GLib.
+ */
+
+static void
+g_mutex_abort (gint         status,
+               const gchar *function)
+{
+  fprintf (stderr, "GLib (gmutex-futex.c): Unexpected error from C library during '%s': %s.  Aborting.\n",
+           strerror (status), function);
+  abort ();
+}
+
+/* {{{1 GMutex */
+
+void
+g_mutex_init (GMutex *mutex)
+{
+  mutex->i[0] = 0;
+}
+
+void
+g_mutex_clear (GMutex *mutex)
+{
+}
+
+static void __attribute__((noinline))
+g_mutex_lock_slowpath (GMutex *mutex)
+{
+  gint value;
+
+  value = __sync_lock_test_and_set (mutex->i, 2);
+
+  while (value != 0)
+    {
+      syscall (__NR_futex, mutex->i, (gsize) FUTEX_WAIT, (gsize) 2, NULL);
+      value = __sync_lock_test_and_set (mutex->i, 2);
+    }
+}
+
+void
+g_mutex_lock (GMutex *mutex)
+{
+  if G_UNLIKELY (!g_atomic_int_compare_and_exchange (mutex->i, 0, 1))
+    g_mutex_lock_slowpath (mutex);
+}
+
+static void __attribute__((noinline))
+g_mutex_unlock_slowpath (GMutex *mutex)
+{
+  g_atomic_int_set (mutex->i, 0);
+  syscall (__NR_futex, mutex->i, (gsize) FUTEX_WAKE, (gsize) 1, NULL);
+}
+
+void
+g_mutex_unlock (GMutex *mutex)
+{
+  if G_UNLIKELY (!g_atomic_int_dec_and_test (mutex->i))
+    g_mutex_unlock_slowpath (mutex);
+}
+
+gboolean
+g_mutex_trylock (GMutex *mutex)
+{
+  return g_atomic_int_compare_and_exchange (mutex->i, 0, 1);
+}
+
+/* {{{1 GRecMutex */
+
+void
+g_rec_mutex_init (GRecMutex *rec_mutex)
+{
+  rec_mutex->i[0] = 0;
+  rec_mutex->i[1] = 0;
+}
+
+void
+g_rec_mutex_clear (GRecMutex *rec_mutex)
+{
+}
+
+static pid_t
+gettid (void)
+{
+  return pthread_self ();
+}
+
+void
+g_rec_mutex_lock (GRecMutex *rec_mutex)
+{
+  pid_t tid = gettid ();
+
+  while (!g_atomic_int_compare_and_exchange (rec_mutex->i, 0, tid))
+    {
+      guint existing = g_atomic_int_get (&rec_mutex->i[0]);
+
+      if (existing == tid)
+        {
+          g_atomic_int_inc (&rec_mutex->i[1]);
+          return;
+        }
+
+      syscall (__NR_futex, rec_mutex->i, (gsize) FUTEX_WAIT, (gsize) existing, NULL);
+    }
+}
+
+void
+g_rec_mutex_unlock (GRecMutex *rec_mutex)
+{
+  if (rec_mutex->i[1] == 0)
+    {
+      g_atomic_int_set (rec_mutex->i, 0);
+      //syscall (__NR_futex, rec_mutex->i, (gsize) FUTEX_WAKE, (gsize) 1, NULL);
+    }
+  else
+    rec_mutex->i[1]--;
+}
+
+gboolean
+g_rec_mutex_trylock (GRecMutex *rec_mutex)
+{
+  pid_t tid = gettid ();
+
+  if (g_atomic_int_compare_and_exchange (rec_mutex->i, 0, tid))
+    return TRUE;
+
+  if (rec_mutex->i[0] == tid)
+    {
+      rec_mutex->i[1]++;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* {{{1 GRWLock */
+
+void
+g_rw_lock_init (GRWLock *lock)
+{
+  lock->i[0] = 0;
+  lock->i[1] = 0;
+}
+
+void
+g_rw_lock_clear (GRWLock *lock)
+{
+}
+
+void
+g_rw_lock_writer_lock (GRWLock *lock)
+{
+  abort ();
+}
+
+gboolean
+g_rw_lock_writer_trylock (GRWLock *lock)
+{
+  abort ();
+}
+
+void
+g_rw_lock_writer_unlock (GRWLock *lock)
+{
+  abort ();
+}
+
+void
+g_rw_lock_reader_lock (GRWLock *lock)
+{
+  abort ();
+}
+
+gboolean
+g_rw_lock_reader_trylock (GRWLock *lock)
+{
+  abort ();
+}
+
+void
+g_rw_lock_reader_unlock (GRWLock *lock)
+{
+  abort ();
+}
+
+/* {{{1 GCond */
+
+void
+g_cond_init (GCond *cond)
+{
+  cond->i[0] = 0;
+}
+
+void
+g_cond_clear (GCond *cond)
+{
+}
+
+void
+g_cond_wait (GCond  *cond,
+             GMutex *mutex)
+{
+  guint sampled = cond->i[0];
+
+  g_mutex_unlock (mutex);
+  syscall (__NR_futex, cond->i, (gsize) FUTEX_WAIT, (gsize) sampled, NULL);
+  g_mutex_lock (mutex);
+}
+
+void
+g_cond_signal (GCond *cond)
+{
+  g_atomic_int_inc (cond->i);
+
+  syscall (__NR_futex, cond->i, (gsize) FUTEX_WAKE, (gsize) 1, NULL);
+}
+
+void
+g_cond_broadcast (GCond *cond)
+{
+  g_atomic_int_inc (cond->i);
+
+  syscall (__NR_futex, cond->i, (gsize) FUTEX_WAKE, (gsize) INT_MAX, NULL);
+}
+
+gboolean
+g_cond_timed_wait (GCond    *cond,
+                   GMutex   *mutex,
+                   GTimeVal *abs_time)
+{
+  abort ();
+}
+
+gboolean
+g_cond_timedwait (GCond  *cond,
+                  GMutex *mutex,
+                  gint64  abs_time)
+{
+  abort ();
+}
+
+/* {{{1 GPrivate */
+
+static pthread_key_t
+g_private_get_impl (GPrivate *key)
+{
+  pthread_key_t impl = (gsize) key->p;
+
+  if G_UNLIKELY (impl == 0)
+    {
+      gint status;
+
+      status = pthread_key_create (&impl, key->notify);
+      if G_UNLIKELY (status != 0)
+        g_mutex_abort (status, "pthread_key_create");
+
+      if (!g_atomic_pointer_compare_and_exchange (&key->p, NULL, (gsize) impl))
+        {
+          pthread_key_delete (impl);
+          impl = (gsize) key->p;
+        }
+    }
+
+  return impl;
+}
+
+gpointer
+g_private_get (GPrivate *key)
+{
+  /* quote POSIX: No errors are returned from pthread_getspecific(). */
+  return pthread_getspecific (g_private_get_impl (key));
+}
+
+void
+g_private_set (GPrivate *key,
+               gpointer  value)
+{
+  gint status;
+
+  if G_UNLIKELY ((status = pthread_setspecific (g_private_get_impl (key), value)) != 0)
+    g_mutex_abort (status, "pthread_setspecific");
+}
+/* {{{1 Epilogue */
+/* vim:set foldmethod=marker: */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]