[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH 3/8] lib/uksched: Introduce thread attributes
Hi Felipe, Please see my comments inline. On 9/25/18 1:01 PM, Felipe Huici wrote: > Hi Costin, > > Please see a few comments inline. > > > On 9/18/18, 5:27 PM, "Costin Lupu" <costin.lupu@xxxxxxxxx> wrote: > >> We introduce thread attributes abstraction which is used for >> configuring thread behaviors. The set of currently available >> attributes was inspired from the pthread interface. > > s/thread attributes/a thread attributes > s/thread behaviors/thread behavior. > >> Thread attributes can be set either when creating the threads or >> during threads execution by calling the corresponding setters. If >> an attribute is not supported by the underlying scheduler then >> -EINVAL is returned by setters. > > s/or during threads/or during thread > >> The detach attribute is common to all threads, regardless the >> scheduling policy, and if set it means that the thread resources >> will be automatically freed on thread exit. By default, threads >> are not detached. The complete detach support will be added in a >> following commit. > > s/regardless/regardless of > >> Time slice and priority make sense only for preemptive schedulers. >> >> Signed-off-by: Costin Lupu <costin.lupu@xxxxxxxxx> >> --- >> lib/uksched/Makefile.uk | 1 + >> lib/uksched/exportsyms.uk | 12 +++ >> lib/uksched/include/uk/sched.h | 75 +++++++++++++++++-- >> lib/uksched/include/uk/thread.h | 12 ++- >> lib/uksched/include/uk/thread_attr.h | 73 +++++++++++++++++++ >> lib/uksched/sched.c | 5 +- >> lib/uksched/thread.c | 34 +++++++++ >> lib/uksched/thread_attr.c | 137 >> +++++++++++++++++++++++++++++++++++ >> lib/ukschedcoop/schedcoop.c | 6 +- >> 9 files changed, 345 insertions(+), 10 deletions(-) >> create mode 100644 lib/uksched/include/uk/thread_attr.h >> create mode 100644 lib/uksched/thread_attr.c >> >> diff --git a/lib/uksched/Makefile.uk b/lib/uksched/Makefile.uk >> index 24816f6..229d847 100644 >> --- a/lib/uksched/Makefile.uk >> +++ b/lib/uksched/Makefile.uk >> @@ -5,3 +5,4 @@ CXXINCLUDES-$(CONFIG_LIBUKSCHED) += >> -I$(LIBUKSCHED_BASE)/include >> >> LIBUKSCHED_SRCS-y += $(LIBUKSCHED_BASE)/sched.c >> LIBUKSCHED_SRCS-y += $(LIBUKSCHED_BASE)/thread.c >> +LIBUKSCHED_SRCS-y += $(LIBUKSCHED_BASE)/thread_attr.c >> diff --git a/lib/uksched/exportsyms.uk b/lib/uksched/exportsyms.uk >> index 45a9694..7d8e102 100644 >> --- a/lib/uksched/exportsyms.uk >> +++ b/lib/uksched/exportsyms.uk >> @@ -14,3 +14,15 @@ uk_thread_fini >> uk_thread_block_timeout >> uk_thread_block >> uk_thread_wake >> +uk_thread_set_prio >> +uk_thread_get_prio >> +uk_thread_set_timeslice >> +uk_thread_get_timeslice >> +uk_thread_attr_init >> +uk_thread_attr_fini >> +uk_thread_attr_set_detachstate >> +uk_thread_attr_get_detachstate >> +uk_thread_attr_set_prio >> +uk_thread_attr_get_prio >> +uk_thread_attr_set_timeslice >> +uk_thread_attr_get_timeslice >> diff --git a/lib/uksched/include/uk/sched.h >> b/lib/uksched/include/uk/sched.h >> index d2fc8df..b21d65c 100644 >> --- a/lib/uksched/include/uk/sched.h >> +++ b/lib/uksched/include/uk/sched.h >> @@ -60,16 +60,31 @@ typedef void (*uk_sched_yield_func_t) >> (struct uk_sched *s); >> >> typedef void (*uk_sched_thread_add_func_t) >> - (struct uk_sched *s, struct uk_thread *t); >> + (struct uk_sched *s, struct uk_thread *t, >> + struct uk_thread_attr *attr); >> typedef void (*uk_sched_thread_remove_func_t) >> (struct uk_sched *s, struct uk_thread *t); >> >> +typedef int (*uk_sched_thread_set_prio_func_t) >> + (struct uk_sched *s, struct uk_thread *t, prio_t prio); >> +typedef int (*uk_sched_thread_get_prio_func_t) >> + (struct uk_sched *s, const struct uk_thread *t, prio_t *prio); >> +typedef int (*uk_sched_thread_set_tslice_func_t) >> + (struct uk_sched *s, struct uk_thread *t, int tslice); >> +typedef int (*uk_sched_thread_get_tslice_func_t) >> + (struct uk_sched *s, const struct uk_thread *t, int *tslice); >> + >> struct uk_sched { >> uk_sched_yield_func_t yield; >> >> uk_sched_thread_add_func_t thread_add; >> uk_sched_thread_remove_func_t thread_remove; >> >> + uk_sched_thread_set_prio_func_t thread_set_prio; >> + uk_sched_thread_get_prio_func_t thread_get_prio; >> + uk_sched_thread_set_tslice_func_t thread_set_tslice; >> + uk_sched_thread_get_tslice_func_t thread_get_tslice; >> + >> /* internal */ >> struct uk_thread idle; >> struct ukplat_ctx_callbacks plat_ctx_cbs; >> @@ -92,12 +107,12 @@ static inline void uk_sched_yield(void) >> } >> >> static inline void uk_sched_thread_add(struct uk_sched *s, >> - struct uk_thread *t) >> + struct uk_thread *t, struct uk_thread_attr *attr) >> { >> UK_ASSERT(s); >> UK_ASSERT(t); >> t->sched = s; >> - s->thread_add(s, t); >> + s->thread_add(s, t, attr); >> } >> >> static inline void uk_sched_thread_remove(struct uk_sched *s, >> @@ -109,6 +124,49 @@ static inline void uk_sched_thread_remove(struct >> uk_sched *s, >> t->sched = NULL; >> } >> >> +static inline int uk_sched_thread_set_prio(struct uk_sched *s, >> + struct uk_thread *t, prio_t prio) >> +{ >> + UK_ASSERT(s); >> + >> + if (!s->thread_set_prio) >> + return -EINVAL; >> + >> + return s->thread_set_prio(s, t, prio); >> +} >> + >> +static inline int uk_sched_thread_get_prio(struct uk_sched *s, >> + const struct uk_thread *t, prio_t *prio) >> +{ >> + UK_ASSERT(s); >> + >> + if (!s->thread_get_prio) >> + return -EINVAL; >> + >> + return s->thread_get_prio(s, t, prio); >> +} >> + >> +static inline int uk_sched_thread_set_timeslice(struct uk_sched *s, >> + struct uk_thread *t, int tslice) >> +{ >> + UK_ASSERT(s); >> + >> + if (!s->thread_set_tslice) >> + return -EINVAL; >> + >> + return s->thread_set_tslice(s, t, tslice); >> +} >> + >> +static inline int uk_sched_thread_get_timeslice(struct uk_sched *s, >> + const struct uk_thread *t, int *tslice) >> +{ >> + UK_ASSERT(s); >> + >> + if (!s->thread_get_tslice) >> + return -EINVAL; >> + >> + return s->thread_get_tslice(s, t, tslice); >> +} >> >> /* >> * Internal scheduler functions >> @@ -132,11 +190,17 @@ static inline struct uk_thread >> *uk_sched_get_idle(struct uk_sched *s) >> void uk_sched_start(struct uk_sched *sched) __noreturn; >> >> #define uk_sched_init(s, yield_func, \ >> - thread_add_func, thread_remove_func) \ >> + thread_add_func, thread_remove_func, \ >> + thread_set_prio_func, thread_get_prio_func, \ >> + thread_set_tslice_func, thread_get_tslice_func) \ >> do { \ >> (s)->yield = yield_func; \ >> (s)->thread_add = thread_add_func; \ >> (s)->thread_remove = thread_remove_func; \ >> + (s)->thread_set_prio = thread_set_prio_func; \ >> + (s)->thread_get_prio = thread_get_prio_func; \ >> + (s)->thread_set_tslice = thread_set_tslice_func; \ >> + (s)->thread_get_tslice = thread_get_tslice_func; \ >> uk_sched_register((s)); \ >> } while (0) >> >> @@ -146,7 +210,8 @@ void uk_sched_start(struct uk_sched *sched) >> __noreturn; >> */ >> >> struct uk_thread *uk_sched_thread_create(struct uk_sched *sched, >> - const char *name, void (*function)(void *), void *arg); >> + const char *name, struct uk_thread_attr *attr, >> + void (*function)(void *), void *arg); >> void uk_sched_thread_destroy(struct uk_sched *sched, >> struct uk_thread *thread); >> >> diff --git a/lib/uksched/include/uk/thread.h >> b/lib/uksched/include/uk/thread.h >> index e66a05b..5ff2dd6 100644 >> --- a/lib/uksched/include/uk/thread.h >> +++ b/lib/uksched/include/uk/thread.h >> @@ -35,6 +35,7 @@ >> #include <uk/arch/lcpu.h> >> #include <uk/arch/time.h> >> #include <uk/plat/thread.h> >> +#include <uk/thread_attr.h> >> #include <uk/list.h> >> #include <uk/essentials.h> >> >> @@ -59,11 +60,20 @@ struct uk_thread { >> >> UK_TAILQ_HEAD(uk_thread_list, struct uk_thread); >> >> +#define uk_thread_create_attr(name, attr, function, data) \ >> + uk_sched_thread_create(uk_sched_get_default(), \ >> + name, attr, function, data) >> #define uk_thread_create(name, function, data) \ >> - uk_sched_thread_create(uk_sched_get_default(), name, function, data) >> + uk_thread_create_attr(name, NULL, function, data) >> #define uk_thread_destroy(thread) \ >> uk_sched_thread_destroy(thread->sched, thread) >> >> +int uk_thread_set_prio(struct uk_thread *thread, prio_t prio); >> +int uk_thread_get_prio(const struct uk_thread *thread, prio_t *prio); >> + >> +int uk_thread_set_timeslice(struct uk_thread *thread, int timeslice); >> +int uk_thread_get_timeslice(const struct uk_thread *thread, int >> *timeslice); >> + >> static inline >> struct uk_thread *uk_thread_current(void) >> { >> diff --git a/lib/uksched/include/uk/thread_attr.h >> b/lib/uksched/include/uk/thread_attr.h >> new file mode 100644 >> index 0000000..30be708 >> --- /dev/null >> +++ b/lib/uksched/include/uk/thread_attr.h >> @@ -0,0 +1,73 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause */ >> +/* >> + * Authors: Costin Lupu <costin.lupu@xxxxxxxxx> >> + * >> + * Copyright (c) 2018, 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 __UK_SCHED_THREAD_ATTR_H__ >> +#define __UK_SCHED_THREAD_ATTR_H__ >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +#define UK_THREAD_ATTR_WAITABLE 0 >> +#define UK_THREAD_ATTR_DETACHED 1 >> + >> +#define UK_THREAD_ATTR_PRIO_MIN 0 >> +#define UK_THREAD_ATTR_PRIO_MAX 255 >> +#define UK_THREAD_ATTR_PRIO_DEFAULT 127 >> + >> +typedef int prio_t; >> + >> +typedef struct uk_thread_attr { >> + int is_detached; >> + prio_t prio; >> + int timeslice; >> +} uk_thread_attr_t; >> + >> +int uk_thread_attr_init(uk_thread_attr_t *attr); >> +int uk_thread_attr_fini(uk_thread_attr_t *attr); >> + >> +int uk_thread_attr_set_detachstate(uk_thread_attr_t *attr, int state); >> +int uk_thread_attr_get_detachstate(const uk_thread_attr_t *attr, int >> *state); >> + >> +int uk_thread_attr_set_prio(uk_thread_attr_t *attr, prio_t prio); >> +int uk_thread_attr_get_prio(const uk_thread_attr_t *attr, prio_t *prio); >> + >> +int uk_thread_attr_set_timeslice(uk_thread_attr_t *attr, int timeslice); >> +int uk_thread_attr_get_timeslice(const uk_thread_attr_t *attr, int >> *timeslice); >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif /* __UK_SCHED_THREAD_ATTR_H__ */ >> diff --git a/lib/uksched/sched.c b/lib/uksched/sched.c >> index 8276e15..f2eca33 100644 >> --- a/lib/uksched/sched.c >> +++ b/lib/uksched/sched.c >> @@ -170,7 +170,8 @@ void uk_sched_idle_init(struct uk_sched *sched, >> } >> >> struct uk_thread *uk_sched_thread_create(struct uk_sched *sched, >> - const char *name, void (*function)(void *), void *arg) >> + const char *name, struct uk_thread_attr *attr, >> + void (*function)(void *), void *arg) >> { >> struct uk_thread *thread = NULL; >> void *stack = NULL; >> @@ -195,7 +196,7 @@ struct uk_thread *uk_sched_thread_create(struct >> uk_sched *sched, >> if (rc) >> goto err; >> >> - uk_sched_thread_add(sched, thread); >> + uk_sched_thread_add(sched, thread, attr); >> >> return thread; >> >> diff --git a/lib/uksched/thread.c b/lib/uksched/thread.c >> index 4b00b1a..a6d90fc 100644 >> --- a/lib/uksched/thread.c >> +++ b/lib/uksched/thread.c >> @@ -30,9 +30,11 @@ >> * Ported from Mini-OS >> */ >> #include <stdlib.h> >> +#include <errno.h> >> #include <uk/plat/config.h> >> #include <uk/plat/time.h> >> #include <uk/thread.h> >> +#include <uk/sched.h> >> #include <uk/print.h> >> #include <uk/assert.h> >> >> @@ -127,3 +129,35 @@ void uk_thread_wake(struct uk_thread *thread) >> thread->wakeup_time = 0LL; >> set_runnable(thread); >> } >> + >> +int uk_thread_set_prio(struct uk_thread *thread, prio_t prio) >> +{ >> + if (!thread) >> + return -EINVAL; >> + >> + return uk_sched_thread_set_prio(thread->sched, thread, prio); >> +} >> + >> +int uk_thread_get_prio(const struct uk_thread *thread, prio_t *prio) >> +{ >> + if (!thread) >> + return -EINVAL; >> + >> + return uk_sched_thread_get_prio(thread->sched, thread, prio); >> +} >> + >> +int uk_thread_set_timeslice(struct uk_thread *thread, int timeslice) >> +{ >> + if (!thread) >> + return -EINVAL; >> + >> + return uk_sched_thread_set_timeslice(thread->sched, thread, timeslice); >> +} >> + >> +int uk_thread_get_timeslice(const struct uk_thread *thread, int >> *timeslice) >> +{ >> + if (!thread) >> + return -EINVAL; >> + >> + return uk_sched_thread_get_timeslice(thread->sched, thread, timeslice); >> +} >> diff --git a/lib/uksched/thread_attr.c b/lib/uksched/thread_attr.c >> new file mode 100644 >> index 0000000..cff1a55 >> --- /dev/null >> +++ b/lib/uksched/thread_attr.c >> @@ -0,0 +1,137 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause */ >> +/* >> + * Authors: Costin Lupu <costin.lupu@xxxxxxxxx> >> + * >> + * Copyright (c) 2018, 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. >> + */ >> + >> +#include <stdlib.h> >> +#include <errno.h> >> +#include <uk/plat/time.h> >> +#include <uk/thread_attr.h> >> +#include <uk/assert.h> >> + >> + >> +int uk_thread_attr_init(uk_thread_attr_t *attr) >> +{ >> + if (attr == NULL) >> + return EINVAL; >> + >> + attr->is_detached = 0; >> + attr->prio = -1; >> + attr->timeslice = 0; >> + >> + return 0; >> +} > > Minor: perhaps define some macros for the 0s and -1s you have here. Also, Ack for prio and timeslice. However, is_detached is a boolean. > return -EINVAL instead of EINVAL. > Same for all uk_thread_attr_* functions below. Ack. > >> + >> +int uk_thread_attr_fini(uk_thread_attr_t *attr) >> +{ >> + if (attr == NULL) >> + return EINVAL; >> + >> + return 0; >> +} >> + >> +int uk_thread_attr_set_detachstate(uk_thread_attr_t *attr, int state) >> +{ >> + if (attr == NULL) >> + return EINVAL; >> + >> + if (state == UK_THREAD_ATTR_DETACHED) >> + attr->is_detached = 1; >> + >> + else if (state == UK_THREAD_ATTR_WAITABLE) >> + attr->is_detached = 0; >> + >> + else >> + return EINVAL; >> + >> + return 0; >> +} > > Shouldn’t you be setting attr’s members to macros, i.e., attr->is_detached > = UK_THREAD_ATTR_DETACHED ? > The parameter is an int, while is_detached is a boolean. >> + >> +int uk_thread_attr_get_detachstate(const uk_thread_attr_t *attr, int >> *state) >> +{ >> + if (attr == NULL || state == NULL) >> + return EINVAL; >> + >> + if (attr->is_detached) >> + *state = UK_THREAD_ATTR_DETACHED; >> + else >> + *state = UK_THREAD_ATTR_WAITABLE; >> + >> + return 0; >> +} >> + >> +int uk_thread_attr_set_prio(uk_thread_attr_t *attr, prio_t prio) >> +{ >> + int rc = EINVAL; >> + >> + if (attr == NULL) >> + return rc; >> + >> + if (prio >= UK_THREAD_ATTR_PRIO_MIN && >> + prio <= UK_THREAD_ATTR_PRIO_MAX) { >> + attr->prio = prio; >> + rc = 0; >> + } >> + >> + return rc; >> +} >> + >> +int uk_thread_attr_get_prio(const uk_thread_attr_t *attr, prio_t *prio) >> +{ >> + if (attr == NULL || prio == NULL) >> + return EINVAL; >> + >> + *prio = attr->prio; >> + >> + return 0; >> +} >> + >> +int uk_thread_attr_set_timeslice(uk_thread_attr_t *attr, int timeslice) >> +{ >> + if (attr == NULL) >> + return EINVAL; >> + >> + /* TODO check timeslice agains platform tick */ >> + attr->timeslice = timeslice; >> + >> + return 0; >> +} > > s/agains/against. Also, when will this be implemented? In v2, since the tick patch was upstreamed recently. > > Thanks, > > — Felipe > >> + >> +int uk_thread_attr_get_timeslice(const uk_thread_attr_t *attr, int >> *timeslice) >> +{ >> + if (attr == NULL || timeslice == NULL) >> + return EINVAL; >> + >> + *timeslice = attr->timeslice; >> + >> + return 0; >> +} >> diff --git a/lib/ukschedcoop/schedcoop.c b/lib/ukschedcoop/schedcoop.c >> index d78ca54..bc02d08 100644 >> --- a/lib/ukschedcoop/schedcoop.c >> +++ b/lib/ukschedcoop/schedcoop.c >> @@ -132,7 +132,8 @@ static void schedcoop_schedule(struct uk_sched *s) >> } >> } >> >> -static void schedcoop_thread_add(struct uk_sched *s, struct uk_thread *t) >> +static void schedcoop_thread_add(struct uk_sched *s, struct uk_thread *t, >> + struct uk_thread_attr *attr __unused) >> { >> unsigned long flags; >> struct schedcoop_private *prv = s->prv; >> @@ -210,7 +211,8 @@ struct uk_sched *uk_schedcoop_init(struct uk_alloc *a) >> uk_sched_init(sched, >> schedcoop_yield, >> schedcoop_thread_add, >> - schedcoop_thread_remove); >> + schedcoop_thread_remove, >> + NULL, NULL, NULL, NULL); >> >> return sched; >> } >> -- >> 2.11.0 >> > > _______________________________________________ > Minios-devel mailing list > Minios-devel@xxxxxxxxxxxxxxxxxxxx > https://lists.xenproject.org/mailman/listinfo/minios-devel > _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |