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

[Minios-devel] [UNIKRAFT PATCH 2/4] lib/uksched: create and delete thread-local storage area



Most of the actual TLS setup is architecture-specific, so sched.c and
thread.c call functions from a header file provided in arch/.

Signed-off-by: Florian Schmidt <florian.schmidt@xxxxxxxxx>
---
 arch/x86/x86_64/include/uk/asm/thread.h | 64 +++++++++++++++++++++++++
 include/uk/arch/thread.h                | 40 ++++++++++++++++
 lib/uksched/include/uk/sched.h          |  3 ++
 lib/uksched/include/uk/thread.h         |  3 +-
 lib/uksched/sched.c                     | 54 ++++++++++++++-------
 lib/uksched/thread.c                    |  8 ++--
 6 files changed, 152 insertions(+), 20 deletions(-)
 create mode 100644 arch/x86/x86_64/include/uk/asm/thread.h
 create mode 100644 include/uk/arch/thread.h

diff --git a/arch/x86/x86_64/include/uk/asm/thread.h 
b/arch/x86/x86_64/include/uk/asm/thread.h
new file mode 100644
index 00000000..6e95848d
--- /dev/null
+++ b/arch/x86/x86_64/include/uk/asm/thread.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Florian Schmidt <florian.schmidt@xxxxxxxxx>
+ *
+ * Copyright (c) 2019, NEC Europe Ltd., NEC Corporation. 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.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __UKARCH_THREAD_H__
+#error Do not include this header directly
+#endif
+
+extern char _tls_start[], _etdata[], _tls_end[];
+
+static inline unsigned long tls_area_size(void)
+{
+       /* x86_64 ABI requires that fs:%0 contains the address of itself, to
+        * allow certain optimizations. Hence, the overall size of the size of
+        * the TLS area, plus 8 bytes.
+        */
+       return _tls_end - _tls_start + 8;
+}
+
+static inline unsigned int tls_area_align(void)
+{
+       return 8;
+}
+
+static inline void tls_copy(void *tls_area)
+{
+       unsigned int tls_len = _tls_end - _tls_start;
+       unsigned int tls_data_len = _etdata - _tls_start;
+       unsigned int tls_bss_len = _tls_end - _etdata;
+
+       memcpy(tls_area, _tls_start, tls_data_len);
+       memset(tls_area+tls_data_len, 0, tls_bss_len);
+       *((uintptr_t *)(tls_area+tls_len)) = (uintptr_t)(tls_area+tls_len);
+}
diff --git a/include/uk/arch/thread.h b/include/uk/arch/thread.h
new file mode 100644
index 00000000..76fd3ad5
--- /dev/null
+++ b/include/uk/arch/thread.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Florian Schmidt <florian.schmidt@xxxxxxxxx>
+ *
+ * Copyright (c) 2019, NEC Europe Ltd., NEC Corporation. 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.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __UKARCH_THREAD_H__
+#define __UKARCH_THREAD_H__
+
+#include <uk/asm/thread.h>
+
+#endif /* __UKARCH_THREAD_H__ */
diff --git a/lib/uksched/include/uk/sched.h b/lib/uksched/include/uk/sched.h
index cc5fbe93..3e21d8d8 100644
--- a/lib/uksched/include/uk/sched.h
+++ b/lib/uksched/include/uk/sched.h
@@ -50,6 +50,9 @@ struct uk_sched;
 
 struct uk_sched *uk_sched_default_init(struct uk_alloc *a);
 
+extern char _tls_start[], _etdata[], _tls_end[];
+#define have_tls_area (_tls_end - _tls_start)
+
 extern struct uk_sched *uk_sched_head;
 int uk_sched_register(struct uk_sched *s);
 struct uk_sched *uk_sched_get_default(void);
diff --git a/lib/uksched/include/uk/thread.h b/lib/uksched/include/uk/thread.h
index 71e39225..8cb3d6b6 100644
--- a/lib/uksched/include/uk/thread.h
+++ b/lib/uksched/include/uk/thread.h
@@ -50,6 +50,7 @@ struct uk_sched;
 struct uk_thread {
        const char *name;
        void *stack;
+       void *tls;
        void *ctx;
        UK_TAILQ_ENTRY(struct uk_thread) thread_list;
        uint32_t flags;
@@ -106,7 +107,7 @@ struct uk_thread *uk_thread_current(void)
 
 int uk_thread_init(struct uk_thread *thread,
                struct ukplat_ctx_callbacks *cbs, struct uk_alloc *allocator,
-               const char *name, void *stack,
+               const char *name, void *stack, void *tls,
                void (*function)(void *), void *arg);
 void uk_thread_fini(struct uk_thread *thread,
                struct uk_alloc *allocator);
diff --git a/lib/uksched/sched.c b/lib/uksched/sched.c
index e0416736..c46db730 100644
--- a/lib/uksched/sched.c
+++ b/lib/uksched/sched.c
@@ -33,10 +33,12 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <uk/plat/config.h>
 #include <uk/plat/thread.h>
 #include <uk/alloc.h>
 #include <uk/sched.h>
+#include <uk/arch/thread.h>
 #if CONFIG_LIBUKSCHEDCOOP
 #include <uk/schedcoop.h>
 #endif
@@ -148,27 +150,42 @@ static void *create_stack(struct uk_alloc *allocator)
        return stack;
 }
 
+static void *uk_thread_tls_create(struct uk_alloc *allocator)
+{
+       void *tls;
+
+       if (uk_posix_memalign(allocator, &tls,
+                               tls_area_align(), tls_area_size()))
+               return NULL;
+       tls_copy(tls);
+       return tls;
+}
+
 void uk_sched_idle_init(struct uk_sched *sched,
                void *stack, void (*function)(void *))
 {
        struct uk_thread *idle;
-       int rc;
+       void *tls = NULL;
 
        UK_ASSERT(sched != NULL);
 
-       if (stack == NULL)
-               stack = create_stack(sched->allocator);
-       UK_ASSERT(stack != NULL);
+       if (!stack && !(stack = create_stack(sched->allocator)))
+               goto out_crash;
+       if (have_tls_area && !(tls = uk_thread_tls_create(sched->allocator)))
+               goto out_crash;
 
        idle = &sched->idle;
 
-       rc = uk_thread_init(idle,
+       if (uk_thread_init(idle,
                        &sched->plat_ctx_cbs, sched->allocator,
-                       "Idle", stack, function, NULL);
-       if (rc)
-               UK_CRASH("Error initializing idle thread.");
+                       "Idle", stack, tls, function, NULL))
+               goto out_crash;
 
        idle->sched = sched;
+       return;
+
+out_crash:
+       UK_CRASH("Error initializing the idle thread.");
 }
 
 struct uk_thread *uk_sched_thread_create(struct uk_sched *sched,
@@ -177,7 +194,7 @@ struct uk_thread *uk_sched_thread_create(struct uk_sched 
*sched,
 {
        struct uk_thread *thread = NULL;
        void *stack = NULL;
-       int rc;
+       void *tls = NULL;
 
        thread = uk_malloc(sched->allocator, sizeof(struct uk_thread));
        if (thread == NULL) {
@@ -188,18 +205,17 @@ struct uk_thread *uk_sched_thread_create(struct uk_sched 
*sched,
        /* We can't use lazy allocation here
         * since the trap handler runs on the stack
         */
-       stack = create_stack(sched->allocator);
-       if (stack == NULL)
+       if (!(stack = create_stack(sched->allocator)))
+               goto err;
+       if (have_tls_area && !(tls = uk_thread_tls_create(sched->allocator)))
                goto err;
 
-       rc = uk_thread_init(thread,
+       if (uk_thread_init(thread,
                        &sched->plat_ctx_cbs, sched->allocator,
-                       name, stack, function, arg);
-       if (rc)
+                       name, stack, tls, function, arg))
                goto err;
 
-       rc = uk_sched_thread_add(sched, thread, attr);
-       if (rc)
+       if (uk_sched_thread_add(sched, thread, attr))
                goto err_add;
 
        return thread;
@@ -207,6 +223,8 @@ struct uk_thread *uk_sched_thread_create(struct uk_sched 
*sched,
 err_add:
        uk_thread_fini(thread, sched->allocator);
 err:
+       if (tls)
+               uk_free(sched->allocator, tls);
        if (stack)
                uk_free(sched->allocator, stack);
        if (thread)
@@ -219,11 +237,15 @@ void uk_sched_thread_destroy(struct uk_sched *sched, 
struct uk_thread *thread)
 {
        UK_ASSERT(sched != NULL);
        UK_ASSERT(thread != NULL);
+       UK_ASSERT(thread->stack != NULL);
+       UK_ASSERT(!have_tls_area || thread->tls != NULL);
        UK_ASSERT(is_exited(thread));
 
        UK_TAILQ_REMOVE(&sched->exited_threads, thread, thread_list);
        uk_thread_fini(thread, sched->allocator);
        uk_pfree(sched->allocator, thread->stack, STACK_SIZE_PAGE_ORDER);
+       if (thread->tls)
+               uk_free(sched->allocator, thread->tls);
        uk_free(sched->allocator, thread);
 }
 
diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c
index 7400baee..a97fad9e 100644
--- a/lib/uksched/thread.c
+++ b/lib/uksched/thread.c
@@ -88,13 +88,14 @@ struct _reent *__getreent(void)
 
 int uk_thread_init(struct uk_thread *thread,
                struct ukplat_ctx_callbacks *cbs, struct uk_alloc *allocator,
-               const char *name, void *stack,
+               const char *name, void *stack, void *tls,
                void (*function)(void *), void *arg)
 {
        unsigned long sp;
 
        UK_ASSERT(thread != NULL);
        UK_ASSERT(stack != NULL);
+       UK_ASSERT(!have_tls_area || tls != NULL);
 
        /* Save pointer to the thread on the stack to get current thread */
        *((unsigned long *) stack) = (unsigned long) thread;
@@ -108,6 +109,7 @@ int uk_thread_init(struct uk_thread *thread,
 
        thread->name = name;
        thread->stack = stack;
+       thread->tls = tls;
 
        /* Not runnable, not exited, not sleeping */
        thread->flags = 0;
@@ -121,8 +123,8 @@ int uk_thread_init(struct uk_thread *thread,
        reent_init(&thread->reent);
 #endif
 
-       uk_pr_info("Thread \"%s\": pointer: %p, stack: %p\n",
-                  name, thread, thread->stack);
+       uk_pr_warn("Thread \"%s\": pointer: %p, stack: %p, tls: %p\n",
+                  name, thread, thread->stack, thread->tls);
 
        return 0;
 }
-- 
2.21.0


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.