|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH 2/4] lib/uksched: create and delete thread-local storage area
Hi Florian,
I'll comment only the minor issues in this mail. Please see inline.
On 5/9/19 4:25 PM, Florian Schmidt wrote:
> Hi Costin, Hi Simon,
>
> On 4/16/19 3:21 PM, Costin Lupu wrote:
>> Hi Florian,
>>
>> Please see my comments inline.
>>
>> On 4/15/19 1:03 PM, Florian Schmidt wrote:
>>> 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
>>
>> I had a discussion with Simon (CCed) a while ago, when I was working on
>> the changes for preemptive scheduling, about where we should put the
>> arch dependent code of threads. We agreed back then to keep it in the
>> plat/ code because arch/ contains only code that is available to user
>> applications as well. This is not the case for the TLS changes since
>> they are private to Unikraft, so please move this to
>> plat/common/include/x86/ . Similarly, .c files for thread arch dependent
>> code should be in plat/common/x86/.
>
> I'll be honest, in my personal opinion, the organization of code that is
> platform *and* architecture specific, and code that is architecture,
> *but not* platform specific, is a huge mess at the moment. For example,
> your reasoning that arch/ should only contain code "available to the
> application" is new to me, I can't remember hearing it before. It's
> certainly one way to structure it, though my first reaction is to
> disagree with this concept. :-) I'd rather have both in arch/, and put
> the "public" functions into one hierarchy, and the "non-public"
> functions in another. If that's even necessary... if an application
> developer wants to manually save and restore their registers, or change
> the stack pointer, or whatever... we give everyone the freedom to shoot
> themselves in the foot with the type of gun they choose.
>
> About architecture-dependent code, I already had many discussion with
> Simon when I did the extended register patch series, and it seems we're
> always ending up where we started. Last time, I just metaphorically
> threw my hands up in the air at some point and put it wherever, part of
> which is why there's x86-specific code in sw_ctx.c (where it patently
> shouldn't be, considering imminent arm support.) My point on your
> comment is thus: I don't care any more where all this code goes. :-) I
> foresee a massive refactoring in the future. Until then, I put the code
> where it makes most sense to me, and am mostly dispassionate about where
> it ends up in the end.
>
> Bottom lime: as long as you two (you and Simon) come up with a
> consistent suggestion where I should put this code, I will go with it
> without any further complains.
>
>
>> Moreover, I would rename it to tls.h and use it also in the next patch
>> instead of thread_switch.h (see the discussion on the next patch).
>
> While it might not seem like it at first glance, this naming is actually
> part of the discussions above. The idea was to eventually move other
> architecture-specific thread switching code (register saving and
> restoring) to that file, too, because that code is solely dependent on
> the architecture and not on the platform. Depending on the outcome of
> the above discussion, I'm fine with a name change though.
>
>>
>>> @@ -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);
>>
>> I know this passes the checkpatch, but please use the Unikraft coding
>> style for the spacing of these 2 lines of code in order to avoid
>> propagating such examples.
>
> Do you mean the spaces around the '+'? I can do that, sure.
>
Yes, please.
>>
>>> +}
>>> 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
>>
>> Same comments as for the location of
>> arch/x86/x86_64/include/uk/asm/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)
>>
>> Given that this is actually a predicate and you don't use uppercase in
>> the name of the macro, renaming it to have_tls_area() might be more
>> suggestive.
>
> Ok, sure, if you think that helps, I'll do it.
>
>>
>>> +
>>> 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()))
>>
>> I believe it would be nice to be able to check the returned value on
>> errors, so please use a variable for that.
>>
>>> + 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;
>>
>> Please don't remove the rc variable. See the comments below.
>>
>>> + 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;
>>
>> Please don't squash these 2 lines since this change makes debugging more
>> difficult. With the original code one can put a breakpoint on the line
>> with the call for create_stack() and check the returned value. I suggest
>> you would use the same approach for the following lines of code as well.
>
> I'm not sure I get your argument. What prevents you from still putting a
> break point on the line and inspecting the return code after the
> changes? Instead of a 'p rc', you do a 'fini' in create_stack, or a 'p
> $rax' after returning from it.
>
I want the breakpoint for only when the function is called (i.e. stack
is not NULL). Even if you would use a conditional breakpoint it would
still complicate things. Besides that, given that is nothing wrong with
the original code, changing it just to look different doesn't sound
right to me.
>>
>>> + 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,
>>
>> Please keep this line as it was because this change make debugging more
>> difficult. We use variables to save the returned values of functions in
>> order to inspect the returned value when debugging. It doesn't hurt the
>> performance at all, so keeping this approach is on the plus side.
>>
>>> &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;
>>
>> Again, please don't remove the rc variable.
>>
>>> + 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;
>>
>> Again, please keep this as it was. Same discussion as above.
>>
>>> + if (have_tls_area && !(tls =
>>> uk_thread_tls_create(sched->allocator)))
>>> goto err;
>>> - rc = uk_thread_init(thread,
>>> + if (uk_thread_init(thread,
>>
>> Same here.
>>
>>> &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))
>>
>> Same here.
>>
>>> 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);
>>
>> When I first saw this usage of have_tls_area I thought it's a (global)
>> variable. But it's not, so that's why I recommend changing it to
>> have_tls_area().
>
> OK, I'll change it.
>
>
>>
>>> 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);
>>
>> Since we're changing this, please change it to uk_pr_debug() instead
>> because:
>> 1) It is a debug message, not a warning.
>> 2) It's exiting counterpart message is printed only for debug.
>> 3) This would flood the output for scenarios when lots of threads are
>> used (e.g. the unit tests of pthread-embedded).
>
> Whoops. Yeah, this is a holdover from my testing where I just wanted it
> to spew out a message every time without having to switch down to "print
> everything". Gonna fix that.
>
>>
>>> return 0;
>>> }
>>>
>
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |