[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v2 3/8] lib/uksched: Introduce thread attributes
Updated the uk_sched_thread_create call in v3. Costin On 1/23/19 4:58 PM, Florian Schmidt wrote: > Ah, one more thing about this patch: You change the signature of > uk_sched_thread_create here, and there is a call in > lib/uknetdev/netdev.c:292 that uses the old signature, so this should > probably be changed just by adding NULL for the attributes. > > Alternatively, this could be changed so that the code uses > uk_thread_create instead, but this would probably require a bit more > refactoring (for example, rx_conf might not even need to contain the > scheduler any more because it could just always use the default > scheduler?) But that's maybe more for Sharan as the original author of > that code to look into. > > Cheers, > Florian > > > On 1/11/19 12:22 AM, Costin Lupu wrote: >> We introduce a thread attributes abstraction which is used for >> configuring thread behavior. The set of currently available >> attributes was inspired from the pthread interface. >> >> Thread attributes can be set either when creating the threads or >> during thread execution by calling the corresponding setters. If >> an attribute is not supported by the underlying scheduler then >> -EINVAL is returned by setters. >> >> The detach attribute is common to all threads, regardless of 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. >> >> 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 | 8 ++ >> lib/uksched/include/uk/sched.h | 75 +++++++++++++++++-- >> lib/uksched/include/uk/thread.h | 12 ++- >> lib/uksched/include/uk/thread_attr.h | 81 ++++++++++++++++++++ >> lib/uksched/sched.c | 5 +- >> lib/uksched/thread.c | 34 +++++++++ >> lib/uksched/thread_attr.c | 139 >> +++++++++++++++++++++++++++++++++++ >> lib/ukschedcoop/schedcoop.c | 6 +- >> 9 files changed, 351 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..0b10405 100644 >> --- a/lib/uksched/exportsyms.uk >> +++ b/lib/uksched/exportsyms.uk >> @@ -14,3 +14,11 @@ uk_thread_fini >> uk_thread_block_timeout >> uk_thread_block >> uk_thread_wake >> +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 >> \ No newline at end of file >> 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..93dcd5c >> --- /dev/null >> +++ b/lib/uksched/include/uk/thread_attr.h >> @@ -0,0 +1,81 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause */ >> +/* >> + * Authors: Costin Lupu <costin.lupu@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 __UK_SCHED_THREAD_ATTR_H__ >> +#define __UK_SCHED_THREAD_ATTR_H__ >> + >> +#include <uk/arch/time.h> >> + >> +#ifdef __cplusplus >> +extern "C" { >> +#endif >> + >> +#define UK_THREAD_ATTR_WAITABLE 0 >> +#define UK_THREAD_ATTR_DETACHED 1 >> + >> +#define UK_THREAD_ATTR_PRIO_INVALID (-1) >> +#define UK_THREAD_ATTR_PRIO_MIN 0 >> +#define UK_THREAD_ATTR_PRIO_MAX 255 >> +#define UK_THREAD_ATTR_PRIO_DEFAULT 127 >> + >> +#define UK_THREAD_ATTR_TIMESLICE_NIL 0 >> + >> +typedef int prio_t; >> + >> +typedef struct uk_thread_attr { >> + /**< Is non-zero if thread should detach */ >> + int is_detached; >> + /**< Priority */ >> + prio_t prio; >> + /**< Time slice in nanoseconds */ >> + __nsec 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, __nsec >> timeslice); >> +int uk_thread_attr_get_timeslice(const uk_thread_attr_t *attr, __nsec >> *timeslice); >> + >> +#ifdef __cplusplus >> +} >> +#endif >> + >> +#endif /* __UK_SCHED_THREAD_ATTR_H__ */ >> diff --git a/lib/uksched/sched.c b/lib/uksched/sched.c >> index c3be206..e855298 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 1236b99..9d06552 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..73845ec >> --- /dev/null >> +++ b/lib/uksched/thread_attr.c >> @@ -0,0 +1,139 @@ >> +/* SPDX-License-Identifier: BSD-3-Clause */ >> +/* >> + * Authors: Costin Lupu <costin.lupu@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. >> + */ >> + >> +#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 = UK_THREAD_ATTR_PRIO_INVALID; >> + attr->timeslice = UK_THREAD_ATTR_TIMESLICE_NIL; >> + >> + return 0; >> +} >> + >> +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; >> +} >> + >> +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, __nsec >> timeslice) >> +{ >> + if (attr == NULL) >> + return -EINVAL; >> + >> + if (timeslice < UKPLAT_TIME_TICK_NSEC) >> + return -EINVAL; >> + >> + attr->timeslice = timeslice; >> + >> + return 0; >> +} >> + >> +int uk_thread_attr_get_timeslice(const uk_thread_attr_t *attr, __nsec >> *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 3e3a92f..97c0d7c 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) >> { >> 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; >> } >> > _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |