bug-hurd
[Top][All Lists]
Advanced

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

[RFC] kern: simple futex for gnumach


From: Marin Ramesa
Subject: [RFC] kern: simple futex for gnumach
Date: Sat, 21 Sep 2013 08:56:42 +0200

This is a preliminary patch, a try at implementation of fast 
userspace locking in gnumach. This futex implementation defines 
only two operations: FUTEX_WAIT and FUTEX_WAKE. FUTEX_WAIT uses
gnumach's simple locks to atomically check for a change of
value at a given address, and if the value after the lock is
still the same it uses thread_suspend() to put the current thread
to sleep. FUTEX_WAIT doesn't support sleeping time intervals for
threads, so a thread must be awakened by FUTEX_WAKE. FUTEX_WAKE
checks the futex at a given address and uses gnumach's 
thread_resume() to awake a number of sleeping threads

There are a number of possible problems with this patch. It only 
allows for 128 addresses to be tracked, each having a maximum number
of 128 sleeping threads. This is for testing purposes only - I
will try to make this number unlimited in principle. Next, it 
does not support time sleeping intervals, so threads must be
awakened by FUTEX_WAKE. Furthermore, it does not undefine already
defined futexes at the given address when all threads have been
awakened, so futexes stay open for suspension of new threads.

Please, comment on this patch. I did not yet test this. I'm having 
some problems running a patched gnumach. 

---
 Makefrag.am  |   2 +
 kern/futex.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 kern/futex.h |  58 +++++++++++++++++++++
 3 files changed, 226 insertions(+)
 create mode 100644 kern/futex.c
 create mode 100644 kern/futex.h

diff --git a/Makefrag.am b/Makefrag.am
index bb08972..4bc0fdd 100644
--- a/Makefrag.am
+++ b/Makefrag.am
@@ -139,6 +139,8 @@ libkernel_a_SOURCES += \
        kern/eventcount.c \
        kern/eventcount.h \
        kern/exception.c \
+       kern/futex.c \
+       kern/futex.h \
        kern/host.c \
        kern/host.h \
        kern/ipc_host.c \
diff --git a/kern/futex.c b/kern/futex.c
new file mode 100644
index 0000000..aba7fb1
--- /dev/null
+++ b/kern/futex.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2013 Marin Ramesa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Fast userspace locking
+ *
+ */
+
+#include <kern/lock.h>
+#include <kern/printf.h>
+#include <kern/futex.h>
+
+/* Number of futexes. */
+static unsigned int num_futexes = 0;
+
+/* Array of futexes. */
+static ftx_t futexes[FUTEX_MAX];
+
+/*
+ * When operation equals FUTEX_WAIT, this is a method for a thread to wait for 
a 
+ * change of value at a given address. FUTEX_WAIT ignores the argument 
thread_num.
+ * Returns 0 if thread has been resumed by FUTEX_WAKE, and -1 if the value at 
the
+ * address has been changed.
+ *
+ * When operation equals FUTEX_WAKE, this is a method for waking up a number
+ * (specified by the argument thread_num) of threads waiting for a change of 
value
+ * at a given address (threads that are in FUTEX_WAIT).
+ *
+ * Return values:
+ *     0 - thread has been resumed by FUTEX_WAKE
+ *     -1 - value at the address has been changed while inside FUTEX_WAIT and 
no
+ *         thread has been suspended
+ *      1 - thread_num threads have been resumed by FUTEX_WAKE
+ *     -2 - FUTEX_WAKE did not found a suspended thread at the passed address
+ *     -3 - maximum number of suspended threads reached at a given address 
inside FUTEX_WAIT
+ *     -4 - maximum number of futexes reached while inside FUTEX_WAIT
+ *     -5 - unknown operation
+ *
+ */
+int futex(int *address, int thread_num, int operation)
+{
+       switch (operation) {
+               case FUTEX_WAIT:
+                       return futex_wait(address);
+                       break;
+               case FUTEX_WAKE:
+                       return futex_wake(address, thread_num);
+                       break;
+               default:
+                       return -5;
+       }       
+}
+
+void futex_init(int *address, ftx_t futex)
+{
+       futex->address = address;
+       futex->num_futexed_threads = 0;
+       futexes[num_futexes] = futex;
+       num_futexes++;
+}
+
+int futex_wait(int *address)
+{
+       lock_t futex_wait_lock;
+
+       /* Save the value at the address. */
+       int temp = *address;
+
+       simple_lock(&futex_wait_lock);
+
+       /* If the value after the lock is still the same. */
+       if (temp == *address) {
+
+               simple_unlock(&futex_wait_lock);
+
+               int i;
+               boolean_t found = FALSE;
+               /* Check if there is an existing futex at the address given. */
+               for (i = 0; i < num_futexes; i++) {
+                       if (futexes[i]->address == address) {
+                               found = TRUE;
+
+                               if (futexes[i]->num_futexed_threads >= 
FUTEX_MAX_THREADS) {
+                                       printf("(futex) maximum number of 
suspended threads reached");
+                                       return -3;
+                               }
+                               /* Add the thread to the futex. */
+                               futexes[i]->futexed_threads
+                                       [futexes[i]->num_futexed_threads] = 
current_thread();
+                               futexes[i]->num_futexed_threads++;
+                               goto suspend;
+                       }
+               }
+               /* If there is no futex, init a new one. */     
+               if (!found) {
+
+                       if (num_futexes - 1 >= FUTEX_MAX) {
+                               printf("(futex) maximum number of futexes 
reached");
+                               return -4;
+                       }
+
+                       ftx_t new_futex;
+                       futex_init(address, new_futex);
+                       num_futexes++;
+                       /* Add the thread to the new futex. */
+                       futexes[num_futexes - 1]->futexed_threads
+                               [futexes[num_futexes - 1]->num_futexed_threads] 
=
+                                       current_thread();
+                       futexes[num_futexes - 1]->num_futexed_threads++;
+               }
+
+               suspend:
+               thread_suspend(current_thread());
+               return 0;
+       }
+       simple_unlock(&futex_wait_lock);
+       return -1;
+}      
+
+int futex_wake(int *address, int thread_num)
+{
+       int i;
+       boolean_t found = FALSE;
+       for (i = 0; i < num_futexes; i++)  
+               if (futexes[i]->address == address) { 
+                       found = TRUE;
+                       break;
+               }
+
+       /* If thread_num is greater than num_futexed_threads, resume all. */
+       if (found && thread_num > futexes[i]->num_futexed_threads)
+               thread_num = futexes[i]->num_futexed_threads - 1;
+
+       if (found) {
+               int j;
+               for (j = 0; j < thread_num; j++) {
+                       thread_resume(futexes[i]->futexed_threads[j]);
+                       futexes[i]->num_futexed_threads--;
+               }
+               return 1;
+       }
+       else return -2;
+}
+
diff --git a/kern/futex.h b/kern/futex.h
new file mode 100644
index 0000000..10ba091
--- /dev/null
+++ b/kern/futex.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Marin Ramesa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KERN_FUTEX_H
+#define _KERN_FUTEX_H
+
+#include <kern/thread.h>
+
+/* Definitions for futex operations. */
+#define FUTEX_WAIT     0
+#define FUTEX_WAKE     1
+
+/* Maximum number of futexed threads waiting at the same address. */
+#define FUTEX_MAX_THREADS      128
+
+/* Maximum number of futexes. */
+#define FUTEX_MAX      128
+
+struct ftx {
+       int *address;
+
+       /* Number of futexed threads at the same address. */
+       unsigned int num_futexed_threads;
+
+       /* Array of futexed threads at the same address. */
+       thread_t futexed_threads[FUTEX_MAX_THREADS];
+};
+
+typedef struct ftx *ftx_t;
+
+extern int futex(int *address, int thread_num, int operation);
+void futex_init(int *address, ftx_t futex);
+int futex_wait(int *address);
+int futex_wake(int *address, int thread_num);
+
+#endif /* _KERN_FUTEX_H */
-- 
1.8.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]