From c2544a8a611a544d97a0d7f3377898afa6567247 Mon Sep 17 00:00:00 2001 From: Gabe Parmer Date: Sun, 5 May 2019 22:21:38 -0400 Subject: [PATCH 01/30] Initial Composite RunTime (crt) support for block points and mutexes - blockpoints added, along with a simple lock on top - added blkpts to sl to support the blkpt library - added a stacklist for stack-allocated block-tracking structures --- .../implementation/tests/crt_tests/Makefile | 8 + .../implementation/tests/crt_tests/crttests.c | 88 ++++++ src/components/include/crt_blkpt.h | 296 ++++++++++++++++++ src/components/include/crt_lock.h | 59 ++++ src/components/include/sl.h | 8 + src/components/include/stacklist.h | 50 +++ src/components/lib/sl/Makefile | 2 +- src/components/lib/sl/sl_blkpt.c | 124 ++++++++ src/platform/i386/runscripts/crttests.sh | 4 + 9 files changed, 638 insertions(+), 1 deletion(-) create mode 100644 src/components/implementation/tests/crt_tests/Makefile create mode 100644 src/components/implementation/tests/crt_tests/crttests.c create mode 100644 src/components/include/crt_blkpt.h create mode 100644 src/components/include/crt_lock.h create mode 100644 src/components/include/stacklist.h create mode 100644 src/components/lib/sl/sl_blkpt.c create mode 100644 src/platform/i386/runscripts/crttests.sh diff --git a/src/components/implementation/tests/crt_tests/Makefile b/src/components/implementation/tests/crt_tests/Makefile new file mode 100644 index 0000000000..1469929f49 --- /dev/null +++ b/src/components/implementation/tests/crt_tests/Makefile @@ -0,0 +1,8 @@ +COMPONENT=crtt.o +INTERFACES= +DEPENDENCIES= +IF_LIB= +ADDITIONAL_LIBS=-lcobj_format $(LIBSLRAW) -lsl_mod_fprr -lsl_thd_static_backend -lsl_blkpt + +include ../../Makefile.subsubdir +MANDITORY_LIB=simple_stklib.o diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c new file mode 100644 index 0000000000..4e0c254e42 --- /dev/null +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -0,0 +1,88 @@ +/* + * Copyright 2016, Phani Gadepalli and Gabriel Parmer, GWU, gparmer@gwu.edu. + * + * This uses a two clause BSD License. + */ + +#include +#include +#include +#include + +#include + +#define LOCK_ITER 10 +#define NTHDS 4 +struct crt_lock lock; +struct sl_thd *lock_thds[NTHDS]; +struct cos_compinfo *ci; + +unsigned int +next_off(unsigned int off) +{ + return cos_thdid() * 7 + 3; +} + +void +lock_thd(void *d) +{ + int i; + unsigned int off = cos_thdid(); + + sl_thd_yield(sl_thd_thdid(lock_thds[1])); + + for (i = 0; i < LOCK_ITER; i++) { + off = next_off(off); + + printc("Thread %d: attempt take\n", cos_thdid()); + crt_lock_take(&lock); + printc("switchto %d -> %d\n", cos_thdid(), sl_thd_thdid(lock_thds[off % NTHDS])); + sl_thd_yield(sl_thd_thdid(lock_thds[off % NTHDS])); + crt_lock_release(&lock); + off = next_off(off); + printc("switchto %d -> %d\n", cos_thdid(), sl_thd_thdid(lock_thds[off % NTHDS])); + sl_thd_yield(sl_thd_thdid(lock_thds[off % NTHDS])); + } +} + +void +test_lock(void) +{ + int i; + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}} + }; + + crt_lock_init(&lock); + + printc("Create threads:\n"); + for (i = 0; i < NTHDS; i++) { + lock_thds[i] = sl_thd_alloc(lock_thd, NULL); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(lock_thds[i]), sps[i].c.value); + sl_thd_param_set(lock_thds[i], sps[i].v); + } +} + +void +cos_init(void) +{ + struct cos_defcompinfo *defci = cos_defcompinfo_curr_get(); + ci = cos_compinfo_get(defci); + + printc("Unit-test for the crt (sl)\n"); + cos_meminfo_init(&(ci->mi), BOOT_MEM_KM_BASE, COS_MEM_KERN_PA_SZ, BOOT_CAPTBL_SELF_UNTYPED_PT); + cos_defcompinfo_init(); + sl_init(SL_MIN_PERIOD_US); + + test_lock(); + + printc("Running benchmark...\n"); + sl_sched_loop_nonblock(); + + assert(0); + + return; +} diff --git a/src/components/include/crt_blkpt.h b/src/components/include/crt_blkpt.h new file mode 100644 index 0000000000..add6c19fe9 --- /dev/null +++ b/src/components/include/crt_blkpt.h @@ -0,0 +1,296 @@ +#ifndef CRT_BLKPT_H +#define CRT_BLKPT_H + +#include +#include +#include + +/*** + * The event count/block point is an abstraction to synchronize the + * blocking behavior of different threads on abstract events. The + * events are usually tied to a specific state of another + * data-structure (into which the blkpt is embedded). For example, a + * lock is taken and released thus generating an event for any + * blocking threads, or a ring buffer has a data item inserted into + * it, thus generating an event for any threads waiting for + * data. Concretely, we want a number of threads to be able to block, + * and a thread to be able to wake up one, or all of them. The + * challenge is solving a single race-condition: + * + * thd 0: check data-structure, determine the need for blocking and + * waiting for an event + * thd 0: preemption, switching to thd 1 + * thd 1: check data-structure, determine that an event is generated + * thd 1: call the scheduler, and wake all blocked threads (not + * including thd 0 yet) + * thd 1: preempt, and switch to thd 0 + * thd 0: call scheduler to block + * + * The resulting state is that thd 1 should have unblocked thd 0, but + * due to a race, the thd 0 will be blocked awaiting the *next* event + * that may never come. Event counts are meant to solve this + * problem. Traditional systems solve this problem using condition + * variables and a lock around the scheduling logic, but if you want + * to decouple the data-structure from the scheduler (e.g. as they are + * in different modes, or components), this is a fundamental problem. + * + * The event count abstraction: + * + * Assume the data-structure generating events has at least three + * states: + * S0: available + * S1: unavailable + * S2: unavailable & subscribed + * + * The transitions within the data-structure are: + * {S0->S1, S1->S0, S1->S2, S2->S0} + * + * Every transition into S0 is an abstract *event*. Threads that look + * at the state of the data-structure, and must block waiting for its + * state to change, wait for such an event to wakeup. + * + * The data-structure must define its own mapping to this state + * machine. A few examples: + * + * Mutexes: + * S0: Not locked. + * S1: Locked and held by thread 0. + * S2: Locked and held by thread 0, and threads 1...N contend the lock + * + * Ring buffer (for simplicity, assuming it never fills): + * S0: data items in ring buffer + * S1: no data in ring buffer + * S2: no data in ring buffer, and thread(s) are waiting for data + * + * The event counts are used to track the threads that use the + * data-structure when transitioning from S1->S2 (block thread), when + * it is in S2 (block additional threads), and when it transitions + * from S2->S0 (wakeup blocked threads). + * + * The event count is used in the following way: + * + * S0->S1: + * data-structure (DS) operation + * E.g. not locked -> locked, or + * dequeue from ring with single data item + * + * S1->S0: + * blkpt_checkpoint(ec) (not used) + * data-structure (DS) operation + * assert(blkpt_has_blocked(ec) == false) (as we're in S1) + * blkpt_trigger(ec) (won't do much as noone is blocked) + * E.g. unlock with no contention, or + * enqueue with no dequeuing threads + * + * S1->S2: + * cp = blkpt_checkpoint(ec) + * data-structure (DS) operation, determine we need to await event + * blkpt_wait(ec, cp) + * retry (this is why event counts can be used with lock-free data-structs) + * E.g. locked -> contended + * empty ring -> waiting for data + * + * S2->S0: + * data-structure (DS) operation + * assert(blkpt_has_blocked(ec) == true) (as we're in S2) + * blkpt_trigger(ec) (wake blocked threads!) + * E.g. unlock with contention, or + * enqueue with dequeuing threads + * + * Event count *optimization*: + * + * We prevent the race above using an epoch (count) for the events + * thus the name. However, to avoid rapid wraparound on the epoch, we + * only increment the epoch when the race condition is possible. That + * is to say, we only increment the event count when the + * data-structure has blocked threads. This not only delays + * wraparound, it also will avoid an atomic instruction for all + * operations that don't involve blocked threads (a common-case, + * exemplified by futexes, for example). + * + * Usage optimization: + * + * Because of the event counter optimization to only use expensive + * operations when triggering there are blocked threads, the user of + * this API can trigger whenever transitioning back to S0. + */ + +struct crt_blkpt { + sched_blkpt_id_t id; + /* most significant bit specifies blocked thds */ + sched_blkpt_epoch_t epoch_blocked; +}; + +struct crt_blkpt_checkpoint { + sched_blkpt_epoch_t epoch_blocked; +}; + +typedef enum { + CRT_BLKPT_UNIPROC = 1, /* are the event operations only called on a single core? */ + CRT_BLKPT_CRIT_SECT = 2, /* is only one thread ever going to trigger at a time? */ +} crt_blkpt_flags_t; + +#define CRT_BLKPT_EPOCH_BLKED_BITS (sizeof(sched_blkpt_epoch_t) * 8) +#define CRT_BLKPT_BLKED_MASK ((1 << (CRT_BLKPT_EPOCH_BLKED_BITS - 2)) - 1) +#define CRT_BLKPT_BLKED(e) ((e) & CRT_BLKPT_BLKED_MASK) +#define CRT_BLKPT_EPOCH(e) ((e) & ~CRT_BLKPT_BLKED_MASK) + +/* Return != 0 on failure: no ids to allocate */ +static inline int +crt_blkpt_init(struct crt_blkpt *blkpt) +{ + sched_blkpt_id_t id; + + id = sched_blkpt_alloc(); + if (id == SCHED_BLKPT_NULL) return -1; + + *blkpt = (struct crt_blkpt){ + .id = id, + .epoch_blocked = 0 + }; + + return 0; +} + +static inline int +crt_blkpt_teardown(struct crt_blkpt *blkpt) +{ + return sched_blkpt_free(blkpt->id); +} + +/* Internal APIs that must be inlined to remove the branches */ +static inline int +__crt_blkpt_atomic_trigger(sched_blkpt_epoch_t *ec, sched_blkpt_epoch_t chkpt, crt_blkpt_flags_t flags) +{ + /* + * Assume that the most significant bit is the blocked + * indicator. This math might reset it to zero, which we want + * to do anyway (as part of CRT_BLKPT_EPOCH). + */ + sched_blkpt_epoch_t new = CRT_BLKPT_EPOCH(chkpt + 1); + + /* inlined so that constant propagation will get rid of condition */ + if (flags == CRT_BLKPT_UNIPROC) { + return ps_upcas(ec, chkpt, new); + } else { + return ps_cas(ec, chkpt, new); + } + /* TODO: faa for CRT_BLKPT_CRIT_SECT? */ +} + +/* + * If we return 1, then the caller will attempt to block, otherwise, + * return 0 and it will re-check the data-structure assuming that + * something happened in the mean time. + */ +static inline int +__crt_blkpt_atomic_wait(sched_blkpt_epoch_t *ec, sched_blkpt_epoch_t chkpt, crt_blkpt_flags_t flags) +{ + sched_blkpt_epoch_t cached = ps_load(ec); + sched_blkpt_epoch_t new = cached | CRT_BLKPT_BLKED_MASK; + int ret; + + /* + * We are the second or later blocker. Blocked already + * set. We're done here. + * + * It isn't clear if it is better to have the additional + * branch here for this to avoid atomic instructions, or to + * just always do the atomic instructions and possibly fail. + */ + if (cached == new) return 1; + + /* function is inlined so that constant propagation will get rid of condition */ + if (flags == CRT_BLKPT_UNIPROC) { + ret = ps_upcas(ec, chkpt, new); + } else { + ret = ps_cas(ec, chkpt, new); + } + if (unlikely(!ret)) { + /* + * CAS failure can mean that 1. another thread + * blocked, and set the blocked bit, or 2. an event is + * triggered. In the former case, we still want to + * block. In the latter case, we want to go back to + * the data-structure. + */ + return ps_load(ec) == new; /* same epoch with blocked set? == success */ + } + + return 1; +} + +/* Trigger an event, waking blocked threads. */ +static inline void +crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) +{ + /* + * Note that the flags should likely be passed in statically, + * as constants. That way they will be inlined the conditions + * in the *_atomic_* function will be removed. + */ + sched_blkpt_epoch_t saved = ps_load(&blkpt->epoch_blocked); + + /* The optimization: don't increment events if noone's listening */ + if (likely(!CRT_BLKPT_BLKED(saved))) return; + + /* slow(er) path for when we have blocked threads */ + if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) { + /* + * Race here between triggering threads. In this case, + * someone else already incremented the epoch and + * unblocked the threads. Yeah, helping algorithms! + */ + return; + } + /* + * Note that there is a race here. Multiple threads triggering + * events might pass different epochs down to the next + * level. This is OK as the next level always takes the epoch + * = max(epoch, ...) (for some wraparound-aware version of + * max). + */ + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved), 0); +} + +/* Wake only a single, specified thread (tracked manually in the data-structure) */ +/* void crt_blkpt_trigger_one(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, cos_thdid_t thdid); */ + +/* + * Checkpoint the state of the current event counter. This checkpoint + * is the one that is active during our operations on the + * data-structure. If we determine that we want to wait for an event + * (thus blocking), then the state of the checkpoint will be compared + * versus the state of the event counter to see if we're working off + * of outdated information. + */ +static inline void +crt_blkpt_checkpoint(struct crt_blkpt *blkpt, struct crt_blkpt_checkpoint *chkpt) +{ + chkpt->epoch_blocked = ps_load(&blkpt->epoch_blocked); +} + +/* Wait for an event. */ +static inline void +crt_blkpt_wait(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, struct crt_blkpt_checkpoint *chkpt) +{ + /* + * If blocked is already set, we can try and block + * directly. Otherwise, go through and try to atomically set + * it. If that fails, then either epoch or blocked has been + * updated, so return and try accessing the data-structure + * again. + */ + if (!CRT_BLKPT_BLKED(chkpt->epoch_blocked) && + !__crt_blkpt_atomic_wait(&blkpt->epoch_blocked, chkpt->epoch_blocked, flags)) return; + + sched_blkpt_block(blkpt->id, CRT_BLKPT_EPOCH(chkpt->epoch_blocked), 0); +} + +/* + * Create an execution dependency on the specified thread for, + * e.g. priority inheritance. + */ +/* void crt_blkpt_wait_dep(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, struct crt_blkpt_checkpoint *chkpt, cos_thdid_t thdid); */ + +#endif /* CRT_BLKPT_H */ diff --git a/src/components/include/crt_lock.h b/src/components/include/crt_lock.h new file mode 100644 index 0000000000..c393c53648 --- /dev/null +++ b/src/components/include/crt_lock.h @@ -0,0 +1,59 @@ +#ifndef CRT_LOCK_H +#define CRT_LOCK_H + +/*** + * Simple blocking lock. Uses blockpoints to enable the blocking and + * waking of contending threads. This has little to no intelligence, + * for example, not expressing dependencies for PI. + */ + +#include +#include + +struct crt_lock { + unsigned long owner; + struct crt_blkpt blkpt; +}; + +static inline int +crt_lock_init(struct crt_lock *l) +{ + l->owner = 0; + + return crt_blkpt_init(&l->blkpt); +} + +static inline int +crt_lock_teardown(struct crt_lock *l) +{ + assert(l->owner == 0); + + return crt_blkpt_teardown(&l->blkpt); +} + +static inline void +crt_lock_take(struct crt_lock *l) +{ + struct crt_blkpt_checkpoint chkpt; + + while (1) { + crt_blkpt_checkpoint(&l->blkpt, &chkpt); + + if (ps_cas(&l->owner, 0, (unsigned long)cos_thdid())) { + return; /* success! */ + } + /* failure: try and block */ + crt_blkpt_wait(&l->blkpt, 0, &chkpt); + } +} + +static inline void +crt_lock_release(struct crt_lock *l) +{ + assert(l->owner == cos_thdid()); + l->owner = 0; + /* if there are blocked threads, wake 'em up! */ + crt_blkpt_trigger(&l->blkpt, 0); +} + +#endif /* CRT_LOCK_H */ diff --git a/src/components/include/sl.h b/src/components/include/sl.h index 1529c7835c..f8c21e2259 100644 --- a/src/components/include/sl.h +++ b/src/components/include/sl.h @@ -70,6 +70,10 @@ struct sl_global_cpu { extern struct sl_global_cpu sl_global_cpu_data[]; +typedef u32_t sched_blkpt_id_t; +#define SCHED_BLKPT_NULL 0 +typedef word_t sched_blkpt_epoch_t; + static inline struct sl_global_cpu * sl__globals_cpu(void) { @@ -120,6 +124,10 @@ sl_thdid(void) return tid; } +sched_blkpt_id_t sched_blkpt_alloc(void); +int sched_blkpt_free(sched_blkpt_id_t id); +int sched_blkpt_trigger(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, int single); +int sched_blkpt_block(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, thdid_t dependency); static inline struct sl_thd * sl_thd_curr(void) diff --git a/src/components/include/stacklist.h b/src/components/include/stacklist.h new file mode 100644 index 0000000000..eb6fb70671 --- /dev/null +++ b/src/components/include/stacklist.h @@ -0,0 +1,50 @@ +#ifndef STACKLIST_H +#define STACKLIST_H + +#include + +struct stacklist_head { + struct ps_list_head head; +}; + +struct stacklist { + thdid_t thdid; + struct ps_list list; +}; + +static inline void +stacklist_init(struct stacklist_head *h) +{ + ps_list_head_init(&h->head); +} + +/* Remove a thread from the list that has been woken */ +static inline void +stacklist_rem(struct stacklist *l) +{ + ps_list_rem_d(l); +} + +/* Add a thread that is going to block */ +static inline void +stacklist_add(struct stacklist_head *h, struct stacklist *l) +{ + ps_list_init_d(l); + ps_list_head_add_d(&h->head, l); +} + +/* Get a thread to wake up, and remove its record! */ +static inline thdid_t +stacklist_dequeue(struct stacklist_head *h) +{ + struct stacklist *sl; + + if (ps_list_head_empty(&h->head)) return 0; + + sl = ps_list_head_first_d(&h->head, struct stacklist); + stacklist_rem(sl); + + return sl->thdid; +} + +#endif /* STACKLIST_H */ diff --git a/src/components/lib/sl/Makefile b/src/components/lib/sl/Makefile index 6e908cda0b..39859fd419 100644 --- a/src/components/lib/sl/Makefile +++ b/src/components/lib/sl/Makefile @@ -1,6 +1,6 @@ include Makefile.src Makefile.comp -LIB_OBJS=sl_capmgr.o sl_raw.o sl_sched.o sl_xcpu.o sl_child.o sl_mod_fprr.o sl_lock.o sl_thd_static_backend.o +LIB_OBJS=sl_capmgr.o sl_raw.o sl_sched.o sl_xcpu.o sl_child.o sl_mod_fprr.o sl_lock.o sl_thd_static_backend.o sl_blkpt.o LIBS=$(LIB_OBJS:%.o=%.a) CINC+=-m32 diff --git a/src/components/lib/sl/sl_blkpt.c b/src/components/lib/sl/sl_blkpt.c new file mode 100644 index 0000000000..400084481d --- /dev/null +++ b/src/components/lib/sl/sl_blkpt.c @@ -0,0 +1,124 @@ +#include +#include + +#define NBLKPTS 64 +struct blkpt_mem { + sched_blkpt_id_t id; + sched_blkpt_epoch_t epoch; + struct stacklist_head blocked; +}; +static struct blkpt_mem __blkpts[NBLKPTS]; +static int __blkpt_offset = 1; + +#define BLKPT_EPOCH_BLKED_BITS ((sizeof(sched_blkpt_epoch_t) * 8) +#define BLKPT_EPOCH_DIFF (BLKPT_EPOCH_BLKED_BITS - 2)/2) +#define BLKPT_BLKED_MASK ((1 << (BLKPT_EPOCH_BLKED_BITS - 2)) - 1) + +static int +blkpt_epoch_expired(sched_blkpt_epoch_t e, sched_blkpt_epoch_t cmp) +{ + return (e > cmp && e - cmp > BLKPT_EPOCH_DIFF) || (e < cmp && cmp - e < BLKPT_EPOCH_DIFF); +} + +static struct blkpt_mem * +blkpt_get(sched_blkpt_id_t id) +{ + if (id - 1 == NBLKPTS) return NULL; + + return &__blkpts[id-1]; +} + +sched_blkpt_id_t +sched_blkpt_alloc(void) +{ + sched_blkpt_id_t id; + struct blkpt_mem *m; + sched_blkpt_id_t ret = SCHED_BLKPT_NULL; + + sl_cs_enter(); + + id = (sched_blkpt_id_t)__blkpt_offset; + m = blkpt_get(id); + if (!m) ERR_THROW(SCHED_BLKPT_NULL, unlock); + + m->id = id; + ret = id; + m->epoch = 0; + stacklist_init(&m->blocked); + __blkpt_offset++; +unlock: + sl_cs_exit(); + + return ret; +} + +int +sched_blkpt_free(sched_blkpt_id_t id) +{ + /* alloc only for now */ + return 0; +} + +int +sched_blkpt_trigger(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, int single) +{ + thdid_t tid; + struct sl_thd *t; + struct blkpt_mem *m; + int ret = 0; + + sl_cs_enter(); + + m = blkpt_get(blkpt); + if (!m) ERR_THROW(-1, unlock); + + /* is the new epoch more recent than the existing? */ + if (!blkpt_epoch_expired(epoch, m->epoch)) ERR_THROW(0, unlock); + + m->epoch = epoch; + while ((tid = stacklist_dequeue(&m->blocked)) != 0) { + t = sl_thd_lkup(tid); + assert(t); + + sl_thd_wakeup_no_cs(t); /* ignore retval: process next thread */ + } + /* most likely we switch to a woken thread here */ + sl_cs_exit_schedule(); + + return 0; +unlock: + sl_cs_exit(); + + return ret; +} + +int +sched_blkpt_block(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, thdid_t dependency) +{ + struct blkpt_mem *m; + struct sl_thd *t; + struct stacklist sl; /* The stack-based structure we'll use to track ourself */ + int ret = 0; + + sl_cs_enter(); + + m = blkpt_get(blkpt); + if (!m) ERR_THROW(-1, unlock); + + /* Outdated event? don't block! */ + if (blkpt_epoch_expired(m->epoch, epoch)) ERR_THROW(0, unlock); + + /* Block! */ + stacklist_add(&m->blocked, &sl); + + t = sl_thd_curr(); + if (sl_thd_block_no_cs(t, SL_THD_BLOCKED, 0)) ERR_THROW(-1, unlock); + + sl_cs_exit_schedule(); + + return 0; +unlock: + sl_cs_exit(); + + return ret; +} diff --git a/src/platform/i386/runscripts/crttests.sh b/src/platform/i386/runscripts/crttests.sh new file mode 100644 index 0000000000..55c6b0792b --- /dev/null +++ b/src/platform/i386/runscripts/crttests.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cp tests.crt_tests.o llboot.o +./cos_linker "llboot.o, :" ./gen_client_stub From fd6df332461bb15bf09ab62fcf33955631240ab3 Mon Sep 17 00:00:00 2001 From: Gabe Parmer Date: Mon, 6 May 2019 14:01:58 -0400 Subject: [PATCH 02/30] Refined the tests for the blkpt-based lock implementation. Note that this is currently NOT multi-core safe as it relies on the sl critical section. Will need to change the stacklist to track trebor stacks of threads to work for multi-core. --- .../implementation/tests/crt_tests/crttests.c | 53 +++++++++++++------ src/components/include/crt_blkpt.h | 8 +-- src/components/include/stacklist.h | 2 + src/components/lib/sl/sl_blkpt.c | 14 +++-- 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 4e0c254e42..d7632a7c17 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -11,38 +11,61 @@ #include -#define LOCK_ITER 10 +#define LOCK_ITER 1000000 #define NTHDS 4 struct crt_lock lock; -struct sl_thd *lock_thds[NTHDS]; +struct sl_thd *lock_thds[NTHDS] = {NULL, }; +unsigned int progress[NTHDS] = {0, }; struct cos_compinfo *ci; -unsigned int -next_off(unsigned int off) +thdid_t +next_thd(void) { - return cos_thdid() * 7 + 3; + return sl_thd_thdid(lock_thds[(unsigned int)(ps_tsc() % NTHDS)]); } +volatile thdid_t holder; + void lock_thd(void *d) { - int i; - unsigned int off = cos_thdid(); + int i, cnt, me = -1; + + for (i = 0; i < NTHDS; i++) { + if (sl_thd_thdid(lock_thds[i]) != cos_thdid()) continue; + + me = i; + } + assert(me != -1); sl_thd_yield(sl_thd_thdid(lock_thds[1])); for (i = 0; i < LOCK_ITER; i++) { - off = next_off(off); - - printc("Thread %d: attempt take\n", cos_thdid()); crt_lock_take(&lock); - printc("switchto %d -> %d\n", cos_thdid(), sl_thd_thdid(lock_thds[off % NTHDS])); - sl_thd_yield(sl_thd_thdid(lock_thds[off % NTHDS])); + + progress[me]++; + holder = cos_thdid(); + + sl_thd_yield(next_thd()); + + if (holder != cos_thdid()) { + printc("FAILURE\n"); + BUG(); + } crt_lock_release(&lock); - off = next_off(off); - printc("switchto %d -> %d\n", cos_thdid(), sl_thd_thdid(lock_thds[off % NTHDS])); - sl_thd_yield(sl_thd_thdid(lock_thds[off % NTHDS])); + sl_thd_yield(next_thd()); } + + for (i = 0; i < NTHDS; i++) { + if (i == me) continue; + + if (progress[i] < LOCK_ITER) { + sl_thd_yield(sl_thd_thdid(lock_thds[i])); + } + } + + printc("SUCCESS!"); + while (1) ; } void diff --git a/src/components/include/crt_blkpt.h b/src/components/include/crt_blkpt.h index add6c19fe9..d647dc50d9 100644 --- a/src/components/include/crt_blkpt.h +++ b/src/components/include/crt_blkpt.h @@ -131,7 +131,7 @@ typedef enum { } crt_blkpt_flags_t; #define CRT_BLKPT_EPOCH_BLKED_BITS (sizeof(sched_blkpt_epoch_t) * 8) -#define CRT_BLKPT_BLKED_MASK ((1 << (CRT_BLKPT_EPOCH_BLKED_BITS - 2)) - 1) +#define CRT_BLKPT_BLKED_MASK (1 << (CRT_BLKPT_EPOCH_BLKED_BITS - 2)) #define CRT_BLKPT_BLKED(e) ((e) & CRT_BLKPT_BLKED_MASK) #define CRT_BLKPT_EPOCH(e) ((e) & ~CRT_BLKPT_BLKED_MASK) @@ -250,7 +250,7 @@ crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) * = max(epoch, ...) (for some wraparound-aware version of * max). */ - sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved), 0); + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 0); } /* Wake only a single, specified thread (tracked manually in the data-structure) */ @@ -284,7 +284,9 @@ crt_blkpt_wait(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, struct crt_blkp if (!CRT_BLKPT_BLKED(chkpt->epoch_blocked) && !__crt_blkpt_atomic_wait(&blkpt->epoch_blocked, chkpt->epoch_blocked, flags)) return; - sched_blkpt_block(blkpt->id, CRT_BLKPT_EPOCH(chkpt->epoch_blocked), 0); + if (unlikely(sched_blkpt_block(blkpt->id, CRT_BLKPT_EPOCH(chkpt->epoch_blocked), 0))) { + BUG(); /* we are using a blkpt id that doesn't exist! */ + } } /* diff --git a/src/components/include/stacklist.h b/src/components/include/stacklist.h index eb6fb70671..2f9f19a63b 100644 --- a/src/components/include/stacklist.h +++ b/src/components/include/stacklist.h @@ -1,6 +1,7 @@ #ifndef STACKLIST_H #define STACKLIST_H +#include #include struct stacklist_head { @@ -31,6 +32,7 @@ stacklist_add(struct stacklist_head *h, struct stacklist *l) { ps_list_init_d(l); ps_list_head_add_d(&h->head, l); + l->thdid = cos_thdid(); } /* Get a thread to wake up, and remove its record! */ diff --git a/src/components/lib/sl/sl_blkpt.c b/src/components/lib/sl/sl_blkpt.c index 400084481d..423649b021 100644 --- a/src/components/lib/sl/sl_blkpt.c +++ b/src/components/lib/sl/sl_blkpt.c @@ -12,12 +12,16 @@ static int __blkpt_offset = 1; #define BLKPT_EPOCH_BLKED_BITS ((sizeof(sched_blkpt_epoch_t) * 8) #define BLKPT_EPOCH_DIFF (BLKPT_EPOCH_BLKED_BITS - 2)/2) -#define BLKPT_BLKED_MASK ((1 << (BLKPT_EPOCH_BLKED_BITS - 2)) - 1) +/* + * Is cmp > e? This is more complicated than it seems it should be + * only because of wrap-around. We have to consider the case that we + * have, and that we haven't wrapped around. + */ static int -blkpt_epoch_expired(sched_blkpt_epoch_t e, sched_blkpt_epoch_t cmp) +blkpt_epoch_is_higher(sched_blkpt_epoch_t e, sched_blkpt_epoch_t cmp) { - return (e > cmp && e - cmp > BLKPT_EPOCH_DIFF) || (e < cmp && cmp - e < BLKPT_EPOCH_DIFF); + return (e > cmp && (e - cmp) > BLKPT_EPOCH_DIFF) || (e < cmp && (cmp - e) < BLKPT_EPOCH_DIFF); } static struct blkpt_mem * @@ -73,7 +77,7 @@ sched_blkpt_trigger(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, int singl if (!m) ERR_THROW(-1, unlock); /* is the new epoch more recent than the existing? */ - if (!blkpt_epoch_expired(epoch, m->epoch)) ERR_THROW(0, unlock); + if (!blkpt_epoch_is_higher(m->epoch, epoch)) ERR_THROW(0, unlock); m->epoch = epoch; while ((tid = stacklist_dequeue(&m->blocked)) != 0) { @@ -106,7 +110,7 @@ sched_blkpt_block(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, thdid_t dep if (!m) ERR_THROW(-1, unlock); /* Outdated event? don't block! */ - if (blkpt_epoch_expired(m->epoch, epoch)) ERR_THROW(0, unlock); + if (blkpt_epoch_is_higher(m->epoch, epoch)) ERR_THROW(0, unlock); /* Block! */ stacklist_add(&m->blocked, &sl); From 6dca32245de8847115eaa8ea52f4a30b66be1262 Mon Sep 17 00:00:00 2001 From: Gabe Parmer Date: Mon, 6 May 2019 20:08:14 -0400 Subject: [PATCH 03/30] Maked one aspect of blockpoints work on multi-core: blocked thread tracking - Simply used a Treiber Stack (CAS-driven stack) that doesn't have ABA problems given the blocking behavior of threads. - Remaining problem: we don't use `sl`'s support to wake threads across cores. --- src/components/include/stacklist.h | 72 +++++++++++++++++++++++------- src/components/lib/sl/sl_blkpt.c | 1 + 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/components/include/stacklist.h b/src/components/include/stacklist.h index 2f9f19a63b..fdd57d0714 100644 --- a/src/components/include/stacklist.h +++ b/src/components/include/stacklist.h @@ -1,38 +1,59 @@ #ifndef STACKLIST_H #define STACKLIST_H -#include -#include +/** + * Modified to support multi-core via a Trebor stack. This is not 100% + * a great solution as it isn't FIFO. However, we release *all* + * threads when unlocking, so the priority scheduling should take over + * at that point. + */ -struct stacklist_head { - struct ps_list_head head; -}; +#include +#include struct stacklist { thdid_t thdid; - struct ps_list list; + struct stacklist *next; +}; + +struct stacklist_head { + struct stacklist *head; }; static inline void stacklist_init(struct stacklist_head *h) { - ps_list_head_init(&h->head); + h->head = NULL; } -/* Remove a thread from the list that has been woken */ -static inline void +/* + * Remove a thread from the list that has been woken. Return 0 on + * success, and 1 if it could not be removed. + */ +static inline int stacklist_rem(struct stacklist *l) { - ps_list_rem_d(l); + /* + * Not currently supported with Trebor Stack. Threads that + * wake early still have to wait their turn. + */ + return 1; } /* Add a thread that is going to block */ static inline void stacklist_add(struct stacklist_head *h, struct stacklist *l) { - ps_list_init_d(l); - ps_list_head_add_d(&h->head, l); l->thdid = cos_thdid(); + l->next = NULL; + assert(h); + + while (1) { + struct stacklist *n = ps_load(&h->head); + + l->next = n; + if (ps_cas((unsigned long *)&h->head, (unsigned long)n, (unsigned long)l)) break; + } } /* Get a thread to wake up, and remove its record! */ @@ -41,12 +62,33 @@ stacklist_dequeue(struct stacklist_head *h) { struct stacklist *sl; - if (ps_list_head_empty(&h->head)) return 0; + if (!h->head) return 0; + + /* + * Only a single thread should trigger an event, and dequeue + * threads, but we'll implement this conservatively. Given + * this, please note that this should *not* iterate more than + * once. + */ + while (1) { + sl = ps_load(&h->head); - sl = ps_list_head_first_d(&h->head, struct stacklist); - stacklist_rem(sl); + if (ps_cas((unsigned long *)&h->head, (unsigned long)sl, (unsigned long)sl->next)) break; + } + sl->next = NULL; return sl->thdid; } +/* + * A thread that wakes up after blocking using a stacklist should be + * able to assume that it is no longer on the list. This enables them + * to assert on that fact. + */ +static inline int +stacklist_is_removed(struct stacklist *l) +{ + return l->next == NULL; +} + #endif /* STACKLIST_H */ diff --git a/src/components/lib/sl/sl_blkpt.c b/src/components/lib/sl/sl_blkpt.c index 423649b021..dac56db1d1 100644 --- a/src/components/lib/sl/sl_blkpt.c +++ b/src/components/lib/sl/sl_blkpt.c @@ -119,6 +119,7 @@ sched_blkpt_block(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, thdid_t dep if (sl_thd_block_no_cs(t, SL_THD_BLOCKED, 0)) ERR_THROW(-1, unlock); sl_cs_exit_schedule(); + assert(stacklist_is_removed(&sl)); /* we cannot still be on the list */ return 0; unlock: From dfbc8cb7ac5abfd1f619defc4848cee66420a75c Mon Sep 17 00:00:00 2001 From: Gabe Parmer Date: Mon, 6 May 2019 20:14:34 -0400 Subject: [PATCH 04/30] Fixed spelling error in stacklist header comment --- src/components/include/stacklist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/include/stacklist.h b/src/components/include/stacklist.h index fdd57d0714..8651a408a7 100644 --- a/src/components/include/stacklist.h +++ b/src/components/include/stacklist.h @@ -2,7 +2,7 @@ #define STACKLIST_H /** - * Modified to support multi-core via a Trebor stack. This is not 100% + * Modified to support multi-core via a Treiber stack. This is not 100% * a great solution as it isn't FIFO. However, we release *all* * threads when unlocking, so the priority scheduling should take over * at that point. From 7d39842395e79f606cb04202ba1f3cd31a05593d Mon Sep 17 00:00:00 2001 From: Gabe Parmer Date: Sat, 11 May 2019 23:23:33 -0400 Subject: [PATCH 05/30] Added primitive, blocking message queue support - Asynchronous by default, and blocking on boundary conditions (queue full/empty) - Macros to inline most of the channel logic and enable the magic of constant propagation - Simple implementation for a single producer, single consumer --- .../implementation/tests/crt_tests/crttests.c | 157 +++++++++++- src/components/include/crt_chan.h | 233 ++++++++++++++++++ 2 files changed, 380 insertions(+), 10 deletions(-) create mode 100644 src/components/include/crt_chan.h diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index d7632a7c17..ac8882afac 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -10,28 +10,164 @@ #include #include +#include + +struct cos_compinfo *ci; + +#define CHAN_ITER 1000000 +#define NCHANTHDS 5 +#define CHAN_BATCH 3 + +CRT_CHAN_STATIC_ALLOC(c0, int, 4); +CRT_CHAN_STATIC_ALLOC(c1, int, 4); +CRT_CHAN_STATIC_ALLOC(c2, int, 4); +CRT_CHAN_STATIC_ALLOC(c3, int, 4); +CRT_CHAN_STATIC_ALLOC(c4, int, 4); + +CRT_CHAN_TYPE_PROTOTYPES(test, int, 4); +struct crt_chan *chans[NCHANTHDS + 1]; +struct sl_thd *chan_thds[NCHANTHDS] = {NULL, }; + +typedef enum { CHILLING = 0, RECVING, SENDING } actions_t; +unsigned long status[NCHANTHDS]; +unsigned long cnts[NCHANTHDS] = {0, }; + +int +chantest_is_deadlocked(void) +{ + int i; + actions_t s = status[0]; + + /* Are all threads in the same blocked state? */ + for (i = 0; i < NCHANTHDS; i++) { + if (status[i] == CHILLING || status[i] != s) return 0; + } + + return 1; +} + +void +chantest_send(int thd_off, struct crt_chan *c) +{ + int send = cos_thdid(); + + if (crt_chan_full_test(c)) status[thd_off] = SENDING; + if (!chantest_is_deadlocked()) { + /* printc("\t%d: send\n", cos_thdid()); */ + crt_chan_send_test(c, &send); + } + status[thd_off] = CHILLING; +} + +void +chantest_recv(int thd_off, struct crt_chan *c) +{ + int recv; + + if (crt_chan_empty_test(c)) status[thd_off] = RECVING; + if (!chantest_is_deadlocked()) { + /* printc("\t%d: recv\n", cos_thdid()); */ + crt_chan_recv_test(c, &recv); + cnts[thd_off]++; + } + status[thd_off] = CHILLING; +} + +void +chan_thd(void *d) +{ + int thd_off = (int)d; + struct crt_chan **chan_pair = &chans[thd_off]; + int recv; + int i; + + for (i = 0; i < CHAN_ITER; i++) { + int j; + + /* printc("%d: pre-send\n", cos_thdid()); */ + for (j = 0; j < CHAN_BATCH; j++) { + chantest_send(thd_off, chan_pair[1]); + } + + /* printc("%d: pre-recv\n", cos_thdid()); */ + for (j = 0; j < CHAN_BATCH; j++) { + chantest_recv(thd_off, chan_pair[0]); + } + } + + printc("SUCCESS! Counts (should be within %d of each other): ", NCHANTHDS * CHAN_BATCH); + for (i = 0; i < NCHANTHDS; i++) { + printc("\t%ld", cnts[i]); + } + printc("\n"); + while (1) ; +} + +void +idle_thd(void *d) +{ + printc("FAILURE: deadlock!\n"); + while (1) ; +} + +void +test_chan(void) +{ + int i; + struct sl_thd *idle; + union sched_param_union idle_param = {.c = {.type = SCHEDP_PRIO, .value = 10}}; + + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 7}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 8}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}} + }; + + chans[0] = c0; + chans[1] = c1; + chans[2] = c2; + chans[3] = c3; + chans[4] = c4; + chans[5] = c0; + + for (i = 0; i < NCHANTHDS; i++) { + crt_chan_init_test(chans[i]); + } + + printc("Create threads:\n"); + for (i = 0; i < NCHANTHDS; i++) { + chan_thds[i] = sl_thd_alloc(chan_thd, (void *)i); + assert(chan_thds[i]); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(chan_thds[i]), sps[i].c.value); + sl_thd_param_set(chan_thds[i], sps[i].v); + } + idle = sl_thd_alloc(idle_thd, NULL); + printc("\tcreating IDLE %d at prio %d\n", sl_thd_thdid(idle), idle_param.c.value); + sl_thd_param_set(idle, idle_param.v); + +} #define LOCK_ITER 1000000 -#define NTHDS 4 +#define NLOCKTHDS 4 struct crt_lock lock; -struct sl_thd *lock_thds[NTHDS] = {NULL, }; -unsigned int progress[NTHDS] = {0, }; -struct cos_compinfo *ci; +struct sl_thd *lock_thds[NLOCKTHDS] = {NULL, }; +unsigned int progress[NLOCKTHDS] = {0, }; +volatile thdid_t holder; thdid_t next_thd(void) { - return sl_thd_thdid(lock_thds[(unsigned int)(ps_tsc() % NTHDS)]); + return sl_thd_thdid(lock_thds[(unsigned int)(ps_tsc() % NLOCKTHDS)]); } -volatile thdid_t holder; - void lock_thd(void *d) { int i, cnt, me = -1; - for (i = 0; i < NTHDS; i++) { + for (i = 0; i < NLOCKTHDS; i++) { if (sl_thd_thdid(lock_thds[i]) != cos_thdid()) continue; me = i; @@ -56,7 +192,7 @@ lock_thd(void *d) sl_thd_yield(next_thd()); } - for (i = 0; i < NTHDS; i++) { + for (i = 0; i < NLOCKTHDS; i++) { if (i == me) continue; if (progress[i] < LOCK_ITER) { @@ -82,7 +218,7 @@ test_lock(void) crt_lock_init(&lock); printc("Create threads:\n"); - for (i = 0; i < NTHDS; i++) { + for (i = 0; i < NLOCKTHDS; i++) { lock_thds[i] = sl_thd_alloc(lock_thd, NULL); printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(lock_thds[i]), sps[i].c.value); sl_thd_param_set(lock_thds[i], sps[i].v); @@ -101,6 +237,7 @@ cos_init(void) sl_init(SL_MIN_PERIOD_US); test_lock(); +// test_chan(); printc("Running benchmark...\n"); sl_sched_loop_nonblock(); diff --git a/src/components/include/crt_chan.h b/src/components/include/crt_chan.h new file mode 100644 index 0000000000..39a06974f4 --- /dev/null +++ b/src/components/include/crt_chan.h @@ -0,0 +1,233 @@ +/* + * Copyright 2019, Gabriel Parmer, GWU, gparmer@gwu.edu. + * + * This uses a two clause BSD License. + */ + +#ifndef CRT_CHAN_H +#define CRT_CHAN_H + +/*** + * + */ + +#include +#include +#include + +struct crt_chan { + u32_t producer; + /* If the ring is empty, recving threads will block on this blkpt. */ + struct crt_blkpt empty; + char _padding1[CACHE_LINE * 2 - (sizeof(struct crt_blkpt) + sizeof(u32_t))]; + u32_t consumer; + /* If the ring is full, sending thread will block on this blkpt. */ + struct crt_blkpt full; + char _padding2[CACHE_LINE * 2 - (sizeof(struct crt_blkpt) + sizeof(u32_t))]; + /* + * @item_sz is a power of two and corresponds to the + * wraparound_mask. The number of data items that the channel + * can hold is item_sz - 1. @wraparound_mask = nslots-1 (were + * nslots is a power of two) + */ + u32_t item_sz, wraparound_mask; + u32_t nslots; + /* The memory for the channel. */ + char mem[0]; +}; + +/* produce a */ +#define CRT_CHAN_STATIC_ALLOC(name, type, nslots) \ +struct __crt_chan_envelope_##name { \ + struct crt_chan c; \ + char mem[nslots * sizeof(type)]; \ +} __##name; \ +struct crt_chan *name = &__##name.c + +#define CRT_CHAN_TYPE_PROTOTYPES(name, type, nslots) \ +static inline int \ +crt_chan_init_##name(struct crt_chan *c) \ +{ return crt_chan_init(c, sizeof(type), nslots); } \ +static inline void \ +crt_chan_teardown_##name(struct crt_chan *c) \ +{ crt_chan_teardown(c); } \ +static inline int \ +crt_chan_empty_##name(struct crt_chan *c) \ +{ return __crt_chan_empty(c, nslots - 1); } \ +static inline int \ +crt_chan_full_##name(struct crt_chan *c) \ +{ return __crt_chan_full(c, nslots - 1); } \ +static inline int \ +crt_chan_send_##name(struct crt_chan *c, void *item) \ +{ \ + assert(pow2(nslots)); \ + return __crt_chan_send(c, item, nslots - 1, sizeof(type)); \ +} \ +static inline int \ +crt_chan_recv_##name(struct crt_chan *c, void *item) \ +{ \ + assert(pow2(nslots)); \ + return __crt_chan_recv(c, item, nslots - 1, sizeof(type)); \ +} \ +static inline int \ +crt_chan_async_send_##name(struct crt_chan *c, void *item) \ +{ \ + assert(pow2(nslots)); \ + if (__crt_chan_produce(c, item, nslots - 1, sizeof(type))) return -EAGAIN; \ + return 0; \ +} \ +static inline int \ +crt_chan_async_recv_##name(struct crt_chan *c, void *item) \ +{ \ + assert(pow2(nslots)); \ + if (__crt_chan_consume(c, item, nslots - 1, sizeof(type))) return -EAGAIN; \ + return 0; \ +} + +#define CRT_CHANCHAN_PROTOTYPES(nslots) \ +CRT_CHAN_TYPE_PROTOTYPES(chan, struct chan *, nslots + +static inline unsigned int +__crt_chan_buff_idx(struct crt_chan *c, u32_t v, u32_t wraparound_mask) +{ return v & wraparound_mask; } + +static inline int +__crt_chan_full(struct crt_chan *c, u32_t wraparound_mask) +{ return c->consumer == __crt_chan_buff_idx(c, c->producer + 1, wraparound_mask); } + +static inline int +__crt_chan_empty(struct crt_chan *c, u32_t wraparound_mask) +{ return c->producer == c->consumer; } + +static inline int +__crt_chan_produce(struct crt_chan *c, void *d, u32_t wraparound_mask, u32_t sz) +{ + if (__crt_chan_full(c, wraparound_mask)) return 1; + memcpy(c->mem + (__crt_chan_buff_idx(c, c->producer, wraparound_mask) * sz), d, sz); + c->producer++; + + return 0; +} + +static inline int +__crt_chan_consume(struct crt_chan *c, void *d, u32_t wraparound_mask, u32_t sz) +{ + void *ret; + + if (__crt_chan_empty(c, wraparound_mask)) return 1; + memcpy(d, c->mem + (__crt_chan_buff_idx(c, c->consumer, wraparound_mask) * sz), sz); + c->consumer++; + + return 0; +} + +/** + * The next two functions pass all of the variables in via arguments, + * so that we can use them for constant propagation along with + * inlining to get rid of the general memcpy code. + */ +static inline int +__crt_chan_send(struct crt_chan *c, void *item, u32_t wraparound_mask, u32_t item_sz) +{ + while (1) { + struct crt_blkpt_checkpoint chkpt; + + crt_blkpt_checkpoint(&c->full, &chkpt); + if (!__crt_chan_produce(c, item, wraparound_mask, item_sz)) { + /* success! */ + crt_blkpt_trigger(&c->empty, 0); + break; + } + crt_blkpt_wait(&c->full, 0, &chkpt); + } + + return 0; +} + +static inline int +__crt_chan_recv(struct crt_chan *c, void *item, u32_t wraparound_mask, u32_t item_sz) +{ + while (1) { + struct crt_blkpt_checkpoint chkpt; + + crt_blkpt_checkpoint(&c->empty, &chkpt); + if (!__crt_chan_consume(c, item, wraparound_mask, item_sz)) { + /* success! */ + crt_blkpt_trigger(&c->full, 0); + break; + } + crt_blkpt_wait(&c->empty, 0, &chkpt); + } + + return 0; +} + + +/* + * We need to know how much to malloc? This function returns that + * requirement. It assumes (and checks) that @slots is a power of two. + */ +static inline int +crt_chan_mem_sz(int item_sz, int slots) +{ + assert(pow2(slots)); + + return sizeof(struct crt_chan) + item_sz * slots; +} + +/* How many slots can we fit into an allocation of a specific mem_sz */ +static inline int +crt_chan_nslots(int item_sz, int mem_sz) +{ + return leqpow2((mem_sz - sizeof(struct crt_chan)) / item_sz); +} + +static inline int +crt_chan_init(struct crt_chan *c, int item_sz, int slots) +{ + assert(pow2(slots)); + if (crt_blkpt_init(&c->empty)) return -1; + if (crt_blkpt_init(&c->full)) return -1; + c->nslots = slots; + c->item_sz = item_sz; + c->wraparound_mask = slots - 1; /* slots is a pow2 */ + + return 0; +} + +static inline void +crt_chan_teardown(struct crt_chan *c) +{ + crt_blkpt_teardown(&c->empty); + crt_blkpt_teardown(&c->full); +} + +/* User-facing send and receive APIs: */ + +static inline int +crt_chan_send(struct crt_chan *c, void *item) +{ + return __crt_chan_send(c, item, c->wraparound_mask, c->item_sz); +} + +static inline int +crt_chan_recv(struct crt_chan *c, void *item) +{ + return __crt_chan_recv(c, item, c->wraparound_mask, c->item_sz); +} + +static inline int +crt_chan_async_send(struct crt_chan *c, void *item) +{ + if (__crt_chan_produce(c, item, c->wraparound_mask, c->item_sz)) return -EAGAIN; + return 0; +} + +static inline int +crt_chan_async_recv(struct crt_chan *c, void *item) +{ + if (__crt_chan_consume(c, item, c->wraparound_mask, c->item_sz)) return -EAGAIN; + return 0; +} + +#endif /* CRT_CHAN_H */ From 2ea471c602c8d420ae811d4eb75b72220d23c194 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 28 Feb 2020 18:51:51 -0500 Subject: [PATCH 06/30] semaphore finished --- src/components/include/crt_lock.h | 82 ++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/src/components/include/crt_lock.h b/src/components/include/crt_lock.h index c393c53648..43a3bb34df 100644 --- a/src/components/include/crt_lock.h +++ b/src/components/include/crt_lock.h @@ -11,49 +11,93 @@ #include struct crt_lock { - unsigned long owner; - struct crt_blkpt blkpt; + unsigned long owner; + struct crt_blkpt blkpt; }; +struct crt_sem { + unsigned long count; + unsigned long max_threads; + struct crt_blkpt blkpt; +}; + +static inline void +crt_sem_up(struct crt_sem *s) +{ + struct crt_blkpt_checkpoint chkpt; + + long unsigned int thd_num_cur = ps_faa(&s->count, 1); + + while(1) + { + crt_blkpt_checkpoint(&s->blkpt, &chkpt); + + if(s->count >= s->max_threads) + { + return; + } + crt_blkpt_wait(&s->blkpt, 0, &chkpt); + } +} + +static inline void +crt_sem_alloc(struct crt_sem *s, int size) +{ + + s->max_threads = size; + s->count = 0; +} + +static inline void +crt_sem_down(struct crt_sem *s) +{ + struct crt_blkpt_checkpoint chkpt; + + long unsigned int thd_num_cur = ps_faa(&s->count, -1); + + crt_blkpt_trigger(&s->blkpt, 0); + +} + static inline int crt_lock_init(struct crt_lock *l) { - l->owner = 0; + l->owner = 0; - return crt_blkpt_init(&l->blkpt); + return crt_blkpt_init(&l->blkpt); } static inline int crt_lock_teardown(struct crt_lock *l) { - assert(l->owner == 0); + assert(l->owner == 0); - return crt_blkpt_teardown(&l->blkpt); + return crt_blkpt_teardown(&l->blkpt); } static inline void crt_lock_take(struct crt_lock *l) { - struct crt_blkpt_checkpoint chkpt; + struct crt_blkpt_checkpoint chkpt; - while (1) { - crt_blkpt_checkpoint(&l->blkpt, &chkpt); + while (1) { + crt_blkpt_checkpoint(&l->blkpt, &chkpt); - if (ps_cas(&l->owner, 0, (unsigned long)cos_thdid())) { - return; /* success! */ - } - /* failure: try and block */ - crt_blkpt_wait(&l->blkpt, 0, &chkpt); - } + if (ps_cas(&l->owner, 0, (unsigned long)cos_thdid())) { + return; /* success! */ + } + /* failure: try and block */ + crt_blkpt_wait(&l->blkpt, 0, &chkpt); + } } static inline void crt_lock_release(struct crt_lock *l) { - assert(l->owner == cos_thdid()); - l->owner = 0; - /* if there are blocked threads, wake 'em up! */ - crt_blkpt_trigger(&l->blkpt, 0); + assert(l->owner == cos_thdid()); + l->owner = 0; + /* if there are blocked threads, wake 'em up! */ + crt_blkpt_trigger(&l->blkpt, 0); } #endif /* CRT_LOCK_H */ From a3226757d965b1d0b22f6d1a1f45ac50d247e248 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Thu, 5 Mar 2020 15:50:25 -0500 Subject: [PATCH 07/30] formatted --- src/components/include/cos_lock.h | 0 src/components/include/crt_lock.h | 40 +++++++++++++------------------ 2 files changed, 16 insertions(+), 24 deletions(-) create mode 100644 src/components/include/cos_lock.h diff --git a/src/components/include/cos_lock.h b/src/components/include/cos_lock.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/components/include/crt_lock.h b/src/components/include/crt_lock.h index 43a3bb34df..d2cba0f90c 100644 --- a/src/components/include/crt_lock.h +++ b/src/components/include/crt_lock.h @@ -11,52 +11,46 @@ #include struct crt_lock { - unsigned long owner; + unsigned long owner; struct crt_blkpt blkpt; }; struct crt_sem { - unsigned long count; - unsigned long max_threads; - struct crt_blkpt blkpt; + unsigned long count; + unsigned long max_threads; + struct crt_blkpt blkpt; }; static inline void crt_sem_up(struct crt_sem *s) { - struct crt_blkpt_checkpoint chkpt; + struct crt_blkpt_checkpoint chkpt; - long unsigned int thd_num_cur = ps_faa(&s->count, 1); + long unsigned int thd_num_cur = ps_faa(&s->count, 1); - while(1) - { - crt_blkpt_checkpoint(&s->blkpt, &chkpt); + while (1) { + crt_blkpt_checkpoint(&s->blkpt, &chkpt); - if(s->count >= s->max_threads) - { - return; - } - crt_blkpt_wait(&s->blkpt, 0, &chkpt); + if (s->count < s->max_threads) { return; } + crt_blkpt_wait (&s->blkpt, 0, &chkpt); } } static inline void crt_sem_alloc(struct crt_sem *s, int size) { - - s->max_threads = size; - s->count = 0; + s->max_threads = size; + s->count = 0; } static inline void crt_sem_down(struct crt_sem *s) { - struct crt_blkpt_checkpoint chkpt; - - long unsigned int thd_num_cur = ps_faa(&s->count, -1); + struct crt_blkpt_checkpoint chkpt; - crt_blkpt_trigger(&s->blkpt, 0); + long unsigned int thd_num_cur = ps_faa(&s->count, -1); + crt_blkpt_trigger(&s->blkpt, 0); } static inline int @@ -83,9 +77,7 @@ crt_lock_take(struct crt_lock *l) while (1) { crt_blkpt_checkpoint(&l->blkpt, &chkpt); - if (ps_cas(&l->owner, 0, (unsigned long)cos_thdid())) { - return; /* success! */ - } + if (ps_cas(&l->owner, 0, (unsigned long)cos_thdid())) { return; /* success! */ } /* failure: try and block */ crt_blkpt_wait(&l->blkpt, 0, &chkpt); } From 4cb27f8962ff5cac6b674eb2cecbb5a39944649c Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Thu, 5 Mar 2020 20:59:09 -0500 Subject: [PATCH 08/30] added single thread wake up --- src/components/lib/sl/sl_blkpt.c | 127 ++++++++++++++++--------------- 1 file changed, 66 insertions(+), 61 deletions(-) diff --git a/src/components/lib/sl/sl_blkpt.c b/src/components/lib/sl/sl_blkpt.c index dac56db1d1..4d09f0d9a4 100644 --- a/src/components/lib/sl/sl_blkpt.c +++ b/src/components/lib/sl/sl_blkpt.c @@ -3,12 +3,12 @@ #define NBLKPTS 64 struct blkpt_mem { - sched_blkpt_id_t id; - sched_blkpt_epoch_t epoch; - struct stacklist_head blocked; + sched_blkpt_id_t id; + sched_blkpt_epoch_t epoch; + struct stacklist_head blocked; }; static struct blkpt_mem __blkpts[NBLKPTS]; -static int __blkpt_offset = 1; +static int __blkpt_offset = 1; #define BLKPT_EPOCH_BLKED_BITS ((sizeof(sched_blkpt_epoch_t) * 8) #define BLKPT_EPOCH_DIFF (BLKPT_EPOCH_BLKED_BITS - 2)/2) @@ -21,109 +21,114 @@ static int __blkpt_offset = 1; static int blkpt_epoch_is_higher(sched_blkpt_epoch_t e, sched_blkpt_epoch_t cmp) { - return (e > cmp && (e - cmp) > BLKPT_EPOCH_DIFF) || (e < cmp && (cmp - e) < BLKPT_EPOCH_DIFF); + return (e > cmp && (e - cmp) > BLKPT_EPOCH_DIFF) || (e < cmp && (cmp - e) < BLKPT_EPOCH_DIFF); } static struct blkpt_mem * blkpt_get(sched_blkpt_id_t id) { - if (id - 1 == NBLKPTS) return NULL; + if (id - 1 == NBLKPTS) return NULL; - return &__blkpts[id-1]; + return &__blkpts[id - 1]; } sched_blkpt_id_t sched_blkpt_alloc(void) { - sched_blkpt_id_t id; - struct blkpt_mem *m; - sched_blkpt_id_t ret = SCHED_BLKPT_NULL; + sched_blkpt_id_t id; + struct blkpt_mem *m; + sched_blkpt_id_t ret = SCHED_BLKPT_NULL; - sl_cs_enter(); + sl_cs_enter(); - id = (sched_blkpt_id_t)__blkpt_offset; - m = blkpt_get(id); - if (!m) ERR_THROW(SCHED_BLKPT_NULL, unlock); + id = (sched_blkpt_id_t)__blkpt_offset; + m = blkpt_get(id); + if (!m) ERR_THROW(SCHED_BLKPT_NULL, unlock); - m->id = id; - ret = id; - m->epoch = 0; - stacklist_init(&m->blocked); - __blkpt_offset++; + m->id = id; + ret = id; + m->epoch = 0; + stacklist_init(&m->blocked); + __blkpt_offset++; unlock: - sl_cs_exit(); + sl_cs_exit(); - return ret; + return ret; } int sched_blkpt_free(sched_blkpt_id_t id) { - /* alloc only for now */ - return 0; + /* alloc only for now */ + return 0; } int sched_blkpt_trigger(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, int single) { - thdid_t tid; - struct sl_thd *t; - struct blkpt_mem *m; - int ret = 0; + thdid_t tid; + struct sl_thd * t; + struct blkpt_mem *m; + int ret = 0; - sl_cs_enter(); + sl_cs_enter(); - m = blkpt_get(blkpt); - if (!m) ERR_THROW(-1, unlock); + m = blkpt_get(blkpt); + if (!m) ERR_THROW(-1, unlock); - /* is the new epoch more recent than the existing? */ - if (!blkpt_epoch_is_higher(m->epoch, epoch)) ERR_THROW(0, unlock); + /* is the new epoch more recent than the existing? */ + if (!blkpt_epoch_is_higher(m->epoch, epoch)) ERR_THROW(0, unlock); - m->epoch = epoch; - while ((tid = stacklist_dequeue(&m->blocked)) != 0) { - t = sl_thd_lkup(tid); - assert(t); + m->epoch = epoch; + while ((tid = stacklist_dequeue(&m->blocked)) != 0) { + t = sl_thd_lkup(tid); + assert(t); - sl_thd_wakeup_no_cs(t); /* ignore retval: process next thread */ - } - /* most likely we switch to a woken thread here */ - sl_cs_exit_schedule(); - return 0; + + sl_thd_wakeup_no_cs(t); /* ignore retval: process next thread */ + + //we woke up one thread and return + if (single == 1) { return; } + } + /* most likely we switch to a woken thread here */ + sl_cs_exit_schedule(); + + return 0; unlock: - sl_cs_exit(); + sl_cs_exit(); - return ret; + return ret; } int sched_blkpt_block(sched_blkpt_id_t blkpt, sched_blkpt_epoch_t epoch, thdid_t dependency) { - struct blkpt_mem *m; - struct sl_thd *t; - struct stacklist sl; /* The stack-based structure we'll use to track ourself */ - int ret = 0; + struct blkpt_mem *m; + struct sl_thd * t; + struct stacklist sl; /* The stack-based structure we'll use to track ourself */ + int ret = 0; - sl_cs_enter(); + sl_cs_enter(); - m = blkpt_get(blkpt); - if (!m) ERR_THROW(-1, unlock); + m = blkpt_get(blkpt); + if (!m) ERR_THROW(-1, unlock); - /* Outdated event? don't block! */ - if (blkpt_epoch_is_higher(m->epoch, epoch)) ERR_THROW(0, unlock); + /* Outdated event? don't block! */ + if (blkpt_epoch_is_higher(m->epoch, epoch)) ERR_THROW(0, unlock); - /* Block! */ - stacklist_add(&m->blocked, &sl); + /* Block! */ + stacklist_add(&m->blocked, &sl); - t = sl_thd_curr(); - if (sl_thd_block_no_cs(t, SL_THD_BLOCKED, 0)) ERR_THROW(-1, unlock); + t = sl_thd_curr(); + if (sl_thd_block_no_cs(t, SL_THD_BLOCKED, 0)) ERR_THROW(-1, unlock); - sl_cs_exit_schedule(); - assert(stacklist_is_removed(&sl)); /* we cannot still be on the list */ + sl_cs_exit_schedule(); + assert(stacklist_is_removed(&sl)); /* we cannot still be on the list */ - return 0; + return 0; unlock: - sl_cs_exit(); + sl_cs_exit(); - return ret; + return ret; } From 3b84e9ef8d3191e7d2cb6df2f3ddb909b76a68ba Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 16:34:37 -0500 Subject: [PATCH 09/30] added READEME.md --- src/components/implementation/tests/crt_tests/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/components/implementation/tests/crt_tests/README.md diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md new file mode 100644 index 0000000000..30ee1e6da7 --- /dev/null +++ b/src/components/implementation/tests/crt_tests/README.md @@ -0,0 +1 @@ +# CRT Tests From be6cc71dc2d68e5556bede00b4482c650be02796 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 16:40:49 -0500 Subject: [PATCH 10/30] added a general blurb about what it crt should do --- .../implementation/tests/crt_tests/README.md | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md index 30ee1e6da7..7662a56fb3 100644 --- a/src/components/implementation/tests/crt_tests/README.md +++ b/src/components/implementation/tests/crt_tests/README.md @@ -1 +1,111 @@ # CRT Tests +``` +The event count/block point is an abstraction to synchronize the + blocking behavior of different threads on abstract events. The + events are usually tied to a specific state of another + data-structure (into which the blkpt is embedded). For example, a + lock is taken and released thus generating an event for any + blocking threads, or a ring buffer has a data item inserted into + it, thus generating an event for any threads waiting for + data. Concretely, we want a number of threads to be able to block, + and a thread to be able to wake up one, or all of them. The + challenge is solving a single race-condition: + + thd 0: check data-structure, determine the need for blocking and + waiting for an event + thd 0: preemption, switching to thd 1 + thd 1: check data-structure, determine that an event is generated + thd 1: call the scheduler, and wake all blocked threads (not + including thd 0 yet) + thd 1: preempt, and switch to thd 0 + thd 0: call scheduler to block + + The resulting state is that thd 1 should have unblocked thd 0, but + due to a race, the thd 0 will be blocked awaiting the next event + that may never come. Event counts are meant to solve this + problem. Traditional systems solve this problem using condition + variables and a lock around the scheduling logic, but if you want + to decouple the data-structure from the scheduler (e.g. as they are + in different modes, or components), this is a fundamental problem. + + The event count abstraction: + + Assume the data-structure generating events has at least three + states: + S0: available + S1: unavailable + S2: unavailable & subscribed + + The transitions within the data-structure are: + {S0->S1, S1->S0, S1->S2, S2->S0} + + Every transition into S0 is an abstract event . Threads that look + at the state of the data-structure, and must block waiting for its + state to change, wait for such an event to wakeup. + + The data-structure must define its own mapping to this state + machine. A few examples: + + Mutexes: + S0: Not locked. + S1: Locked and held by thread 0. + S2: Locked and held by thread 0, and threads 1...N contend the lock + + Ring buffer (for simplicity, assuming it never fills): + S0: data items in ring buffer + S1: no data in ring buffer + S2: no data in ring buffer, and thread(s) are waiting for data + + The event counts are used to track the threads that use the + data-structure when transitioning from S1->S2 (block thread), when + it is in S2 (block additional threads), and when it transitions + from S2->S0 (wakeup blocked threads). + + The event count is used in the following way: + + S0->S1: + data-structure (DS) operation + E.g. not locked -> locked, or + dequeue from ring with single data item + + S1->S0: + blkpt_checkpoint(ec) (not used) + data-structure (DS) operation + assert(blkpt_has_blocked(ec) == false) (as we're in S1) + blkpt_trigger(ec) (won't do much as noone is blocked) + E.g. unlock with no contention, or + enqueue with no dequeuing threads + + S1->S2: + cp = blkpt_checkpoint(ec) + data-structure (DS) operation, determine we need to await event + blkpt_wait(ec, cp) + retry (this is why event counts can be used with lock-free data-structs) + E.g. locked -> contended + empty ring -> waiting for data + + S2->S0: + data-structure (DS) operation + assert(blkpt_has_blocked(ec) == true) (as we're in S2) + blkpt_trigger(ec) (wake blocked threads!) + E.g. unlock with contention, or + enqueue with dequeuing threads + + Event count optimization : + + We prevent the race above using an epoch (count) for the events + thus the name. However, to avoid rapid wraparound on the epoch, we + only increment the epoch when the race condition is possible. That + is to say, we only increment the event count when the + data-structure has blocked threads. This not only delays + wraparound, it also will avoid an atomic instruction for all + operations that don't involve blocked threads (a common-case, + exemplified by futexes, for example). + + Usage optimization: + + Because of the event counter optimization to only use expensive + operations when triggering there are blocked threads, the user of + this API can trigger whenever transitioning back to S0. + ``` +- [ ] From b3fb0223b4872b206c8ac68c4d8920fbfbc5e9af Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 16:41:58 -0500 Subject: [PATCH 11/30] added a general blurb about what it crt should do --- src/components/implementation/tests/crt_tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md index 7662a56fb3..2375ed2272 100644 --- a/src/components/implementation/tests/crt_tests/README.md +++ b/src/components/implementation/tests/crt_tests/README.md @@ -108,4 +108,4 @@ The event count/block point is an abstraction to synchronize the operations when triggering there are blocked threads, the user of this API can trigger whenever transitioning back to S0. ``` -- [ ] +- [] From 5a24b643c37344455e2de0fcb246565f1c1ee98c Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 16:43:10 -0500 Subject: [PATCH 12/30] added a general blurb about what it crt should do --- src/components/implementation/tests/crt_tests/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md index 2375ed2272..f2dc0842e1 100644 --- a/src/components/implementation/tests/crt_tests/README.md +++ b/src/components/implementation/tests/crt_tests/README.md @@ -108,4 +108,5 @@ The event count/block point is an abstraction to synchronize the operations when triggering there are blocked threads, the user of this API can trigger whenever transitioning back to S0. ``` -- [] + +- [ ] Test 1 From a32c8c4b88cbdd670fa665413ba05c2179a84946 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 16:45:10 -0500 Subject: [PATCH 13/30] added some formatting --- src/components/implementation/tests/crt_tests/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md index f2dc0842e1..6c8985c3f8 100644 --- a/src/components/implementation/tests/crt_tests/README.md +++ b/src/components/implementation/tests/crt_tests/README.md @@ -1,4 +1,6 @@ # CRT Tests + +## General Description of crt blkpt ``` The event count/block point is an abstraction to synchronize the blocking behavior of different threads on abstract events. The @@ -109,4 +111,6 @@ The event count/block point is an abstraction to synchronize the this API can trigger whenever transitioning back to S0. ``` -- [ ] Test 1 +## Tests to implement + +- [ ] Basic Premption Check From c455bf28f098953df5c130e31a47dac256d40ca5 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 17:35:24 -0500 Subject: [PATCH 14/30] added thoughts about first test --- .../implementation/tests/crt_tests/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md index 6c8985c3f8..e84df2eb23 100644 --- a/src/components/implementation/tests/crt_tests/README.md +++ b/src/components/implementation/tests/crt_tests/README.md @@ -114,3 +114,15 @@ The event count/block point is an abstraction to synchronize the ## Tests to implement - [ ] Basic Premption Check + +We will have a thread preempt another thread using thd_yield(). + +Pseudocode +``` +set up a checkpoint on a thread +preempt said thread using thd_yield() +wake up all thds +switch to thd original thd +block thd (no one will wake this thd up) + +``` From d4c20c6b31d32e037d5d6c238a03112e76fe2af8 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 17:36:18 -0500 Subject: [PATCH 15/30] added thoughts about first test --- .../implementation/tests/crt_tests/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md index e84df2eb23..fef09ba87e 100644 --- a/src/components/implementation/tests/crt_tests/README.md +++ b/src/components/implementation/tests/crt_tests/README.md @@ -119,10 +119,10 @@ We will have a thread preempt another thread using thd_yield(). Pseudocode ``` -set up a checkpoint on a thread -preempt said thread using thd_yield() -wake up all thds -switch to thd original thd -block thd (no one will wake this thd up) +- set up a checkpoint on a thread +- preempt said thread using thd_yield() +- wake up all thds +- switch to thd original thd +- block thd (no one will wake this thd up) ``` From 8cfa6985e81f05e003e4bcbad17d4e389507b089 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Fri, 6 Mar 2020 17:37:21 -0500 Subject: [PATCH 16/30] added thoughts about first test --- src/components/implementation/tests/crt_tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/implementation/tests/crt_tests/README.md b/src/components/implementation/tests/crt_tests/README.md index fef09ba87e..71793119b3 100644 --- a/src/components/implementation/tests/crt_tests/README.md +++ b/src/components/implementation/tests/crt_tests/README.md @@ -122,7 +122,7 @@ Pseudocode - set up a checkpoint on a thread - preempt said thread using thd_yield() - wake up all thds -- switch to thd original thd +- switch to original thd - block thd (no one will wake this thd up) ``` From 73a41073ef3c9e43fd641304651fca9b781aaf6e Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Sat, 7 Mar 2020 15:57:58 -0500 Subject: [PATCH 17/30] added initial tests not working --- .../implementation/tests/crt_tests/crttests.c | 336 ++++++++++-------- 1 file changed, 197 insertions(+), 139 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index ac8882afac..68f58c4eee 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -18,6 +18,7 @@ struct cos_compinfo *ci; #define NCHANTHDS 5 #define CHAN_BATCH 3 + CRT_CHAN_STATIC_ALLOC(c0, int, 4); CRT_CHAN_STATIC_ALLOC(c1, int, 4); CRT_CHAN_STATIC_ALLOC(c2, int, 4); @@ -35,117 +36,117 @@ unsigned long cnts[NCHANTHDS] = {0, }; int chantest_is_deadlocked(void) { - int i; - actions_t s = status[0]; + int i; + actions_t s = status[0]; - /* Are all threads in the same blocked state? */ - for (i = 0; i < NCHANTHDS; i++) { - if (status[i] == CHILLING || status[i] != s) return 0; - } + /* Are all threads in the same blocked state? */ + for (i = 0; i < NCHANTHDS; i++) { + if (status[i] == CHILLING || status[i] != s) return 0; + } - return 1; + return 1; } void chantest_send(int thd_off, struct crt_chan *c) { - int send = cos_thdid(); - - if (crt_chan_full_test(c)) status[thd_off] = SENDING; - if (!chantest_is_deadlocked()) { - /* printc("\t%d: send\n", cos_thdid()); */ - crt_chan_send_test(c, &send); - } - status[thd_off] = CHILLING; + int send = cos_thdid(); + + if (crt_chan_full_test(c)) status[thd_off] = SENDING; + if (!chantest_is_deadlocked()) { + /* printc("\t%d: send\n", cos_thdid()); */ + crt_chan_send_test(c, &send); + } + status[thd_off] = CHILLING; } void chantest_recv(int thd_off, struct crt_chan *c) { - int recv; - - if (crt_chan_empty_test(c)) status[thd_off] = RECVING; - if (!chantest_is_deadlocked()) { - /* printc("\t%d: recv\n", cos_thdid()); */ - crt_chan_recv_test(c, &recv); - cnts[thd_off]++; - } - status[thd_off] = CHILLING; + int recv; + + if (crt_chan_empty_test(c)) status[thd_off] = RECVING; + if (!chantest_is_deadlocked()) { + /* printc("\t%d: recv\n", cos_thdid()); */ + crt_chan_recv_test(c, &recv); + cnts[thd_off]++; + } + status[thd_off] = CHILLING; } void chan_thd(void *d) { - int thd_off = (int)d; - struct crt_chan **chan_pair = &chans[thd_off]; - int recv; - int i; - - for (i = 0; i < CHAN_ITER; i++) { - int j; - - /* printc("%d: pre-send\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { - chantest_send(thd_off, chan_pair[1]); - } - - /* printc("%d: pre-recv\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { - chantest_recv(thd_off, chan_pair[0]); - } - } - - printc("SUCCESS! Counts (should be within %d of each other): ", NCHANTHDS * CHAN_BATCH); - for (i = 0; i < NCHANTHDS; i++) { - printc("\t%ld", cnts[i]); - } - printc("\n"); - while (1) ; + int thd_off = (int)d; + struct crt_chan **chan_pair = &chans[thd_off]; + int recv; + int i; + + for (i = 0; i < CHAN_ITER; i++) { + int j; + + /* printc("%d: pre-send\n", cos_thdid()); */ + for (j = 0; j < CHAN_BATCH; j++) { + chantest_send(thd_off, chan_pair[1]); + } + + /* printc("%d: pre-recv\n", cos_thdid()); */ + for (j = 0; j < CHAN_BATCH; j++) { + chantest_recv(thd_off, chan_pair[0]); + } + } + + printc("SUCCESS! Counts (should be within %d of each other): ", NCHANTHDS * CHAN_BATCH); + for (i = 0; i < NCHANTHDS; i++) { + printc("\t%ld", cnts[i]); + } + printc("\n"); + while (1) ; } void idle_thd(void *d) { - printc("FAILURE: deadlock!\n"); - while (1) ; + printc("FAILURE: deadlock!\n"); + while (1) ; } void test_chan(void) { - int i; - struct sl_thd *idle; - union sched_param_union idle_param = {.c = {.type = SCHEDP_PRIO, .value = 10}}; - - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 7}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 8}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}} - }; - - chans[0] = c0; - chans[1] = c1; - chans[2] = c2; - chans[3] = c3; - chans[4] = c4; - chans[5] = c0; - - for (i = 0; i < NCHANTHDS; i++) { - crt_chan_init_test(chans[i]); - } - - printc("Create threads:\n"); - for (i = 0; i < NCHANTHDS; i++) { - chan_thds[i] = sl_thd_alloc(chan_thd, (void *)i); - assert(chan_thds[i]); - printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(chan_thds[i]), sps[i].c.value); - sl_thd_param_set(chan_thds[i], sps[i].v); - } - idle = sl_thd_alloc(idle_thd, NULL); - printc("\tcreating IDLE %d at prio %d\n", sl_thd_thdid(idle), idle_param.c.value); - sl_thd_param_set(idle, idle_param.v); + int i; + struct sl_thd *idle; + union sched_param_union idle_param = {.c = {.type = SCHEDP_PRIO, .value = 10}}; + + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 7}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 8}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}} + }; + + chans[0] = c0; + chans[1] = c1; + chans[2] = c2; + chans[3] = c3; + chans[4] = c4; + chans[5] = c0; + + for (i = 0; i < NCHANTHDS; i++) { + crt_chan_init_test(chans[i]); + } + + printc("Create threads:\n"); + for (i = 0; i < NCHANTHDS; i++) { + chan_thds[i] = sl_thd_alloc(chan_thd, (void *)i); + assert(chan_thds[i]); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(chan_thds[i]), sps[i].c.value); + sl_thd_param_set(chan_thds[i], sps[i].v); + } + idle = sl_thd_alloc(idle_thd, NULL); + printc("\tcreating IDLE %d at prio %d\n", sl_thd_thdid(idle), idle_param.c.value); + sl_thd_param_set(idle, idle_param.v); } @@ -159,90 +160,147 @@ volatile thdid_t holder; thdid_t next_thd(void) { - return sl_thd_thdid(lock_thds[(unsigned int)(ps_tsc() % NLOCKTHDS)]); + return sl_thd_thdid(lock_thds[(unsigned int)(ps_tsc() % NLOCKTHDS)]); } void lock_thd(void *d) { - int i, cnt, me = -1; + int i, cnt, me = -1; - for (i = 0; i < NLOCKTHDS; i++) { - if (sl_thd_thdid(lock_thds[i]) != cos_thdid()) continue; + for (i = 0; i < NLOCKTHDS; i++) { + if (sl_thd_thdid(lock_thds[i]) != cos_thdid()) continue; - me = i; - } - assert(me != -1); + me = i; + } + assert(me != -1); - sl_thd_yield(sl_thd_thdid(lock_thds[1])); + sl_thd_yield(sl_thd_thdid(lock_thds[1])); - for (i = 0; i < LOCK_ITER; i++) { - crt_lock_take(&lock); + for (i = 0; i < LOCK_ITER; i++) { + crt_lock_take(&lock); - progress[me]++; - holder = cos_thdid(); + progress[me]++; + holder = cos_thdid(); - sl_thd_yield(next_thd()); + sl_thd_yield(next_thd()); - if (holder != cos_thdid()) { - printc("FAILURE\n"); - BUG(); - } - crt_lock_release(&lock); - sl_thd_yield(next_thd()); - } + if (holder != cos_thdid()) { + printc("FAILURE\n"); + BUG(); + } + crt_lock_release(&lock); + sl_thd_yield(next_thd()); + } - for (i = 0; i < NLOCKTHDS; i++) { - if (i == me) continue; + for (i = 0; i < NLOCKTHDS; i++) { + if (i == me) continue; - if (progress[i] < LOCK_ITER) { - sl_thd_yield(sl_thd_thdid(lock_thds[i])); - } - } + if (progress[i] < LOCK_ITER) { + sl_thd_yield(sl_thd_thdid(lock_thds[i])); + } + } - printc("SUCCESS!"); - while (1) ; + printc("SUCCESS!"); + while (1) ; } void test_lock(void) { - int i; - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}} - }; - - crt_lock_init(&lock); - - printc("Create threads:\n"); - for (i = 0; i < NLOCKTHDS; i++) { - lock_thds[i] = sl_thd_alloc(lock_thd, NULL); - printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(lock_thds[i]), sps[i].c.value); - sl_thd_param_set(lock_thds[i], sps[i].v); - } + int i; + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}} + }; + + crt_lock_init(&lock); + + printc("Create threads:\n"); + for (i = 0; i < NLOCKTHDS; i++) { + lock_thds[i] = sl_thd_alloc(lock_thd, NULL); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(lock_thds[i]), sps[i].c.value); + sl_thd_param_set(lock_thds[i], sps[i].v); + } +} + +#define NBLKTHDS 4 +struct sl_thd *blk_thds[NBLKTHDS] = {NULL, }; + +void +blk_thd(void *d) +{ + struct crt_blkpt_checkpoint chkpt; + struct crt_blkpt blkpt; + + + /* wake up all threads */ + crt_blkpt_trigger(&blkpt, 0); + + /* set up a checkoint */ + crt_blkpt_checkpoint(&blkpt, &chkpt); + + /* prempt thread */ + sl_thd_yield(sl_thd_thdid(blk_thds[1])); + + /* go back to original thread */ + sl_thd_yield(sl_thd_thdid(blk_thds[0])); + + /* block and hopefully someone should wake us up */ + crt_blkpt_wait(&blkpt, 0, &chkpt); + + if(me == 0) + { + printc("SUCCESS"); + } + + while(1); +} + + + +void +test_blkpt(void) +{ + int i; + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}} + }; + + printc("Create threads:\n"); + for (i = 0; i < NBLKTHDS; i++) { + blk_thds[i] = sl_thd_alloc(blk_thd, NULL); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[i]), sps[i].c.value); + sl_thd_param_set(blk_thds[i], sps[i].v); + } + } void cos_init(void) { - struct cos_defcompinfo *defci = cos_defcompinfo_curr_get(); - ci = cos_compinfo_get(defci); + struct cos_defcompinfo *defci = cos_defcompinfo_curr_get(); + ci = cos_compinfo_get(defci); - printc("Unit-test for the crt (sl)\n"); - cos_meminfo_init(&(ci->mi), BOOT_MEM_KM_BASE, COS_MEM_KERN_PA_SZ, BOOT_CAPTBL_SELF_UNTYPED_PT); - cos_defcompinfo_init(); - sl_init(SL_MIN_PERIOD_US); + printc("Unit-test for the crt (sl)\n"); + cos_meminfo_init(&(ci->mi), BOOT_MEM_KM_BASE, COS_MEM_KERN_PA_SZ, BOOT_CAPTBL_SELF_UNTYPED_PT); + cos_defcompinfo_init(); + sl_init(SL_MIN_PERIOD_US); - test_lock(); + //test_lock(); // test_chan(); - printc("Running benchmark...\n"); - sl_sched_loop_nonblock(); + test_blkpt(); + + printc("Running benchmark...\n"); + sl_sched_loop_nonblock(); - assert(0); + assert(0); - return; + return; } From b2c474bda69e9e2b93723799f90e5c1728fd2d88 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Sat, 7 Mar 2020 15:59:41 -0500 Subject: [PATCH 18/30] formatting --- .../implementation/tests/crt_tests/crttests.c | 129 +++++++++--------- 1 file changed, 63 insertions(+), 66 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 68f58c4eee..c86369b0f9 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -14,8 +14,8 @@ struct cos_compinfo *ci; -#define CHAN_ITER 1000000 -#define NCHANTHDS 5 +#define CHAN_ITER 1000000 +#define NCHANTHDS 5 #define CHAN_BATCH 3 @@ -27,16 +27,25 @@ CRT_CHAN_STATIC_ALLOC(c4, int, 4); CRT_CHAN_TYPE_PROTOTYPES(test, int, 4); struct crt_chan *chans[NCHANTHDS + 1]; -struct sl_thd *chan_thds[NCHANTHDS] = {NULL, }; +struct sl_thd * chan_thds[NCHANTHDS] = { + NULL, +}; -typedef enum { CHILLING = 0, RECVING, SENDING } actions_t; +typedef enum +{ + CHILLING = 0, + RECVING, + SENDING +} actions_t; unsigned long status[NCHANTHDS]; -unsigned long cnts[NCHANTHDS] = {0, }; +unsigned long cnts[NCHANTHDS] = { + 0, +}; int chantest_is_deadlocked(void) { - int i; + int i; actions_t s = status[0]; /* Are all threads in the same blocked state? */ @@ -77,54 +86,48 @@ chantest_recv(int thd_off, struct crt_chan *c) void chan_thd(void *d) { - int thd_off = (int)d; + int thd_off = (int)d; struct crt_chan **chan_pair = &chans[thd_off]; - int recv; - int i; + int recv; + int i; for (i = 0; i < CHAN_ITER; i++) { int j; /* printc("%d: pre-send\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { - chantest_send(thd_off, chan_pair[1]); - } + for (j = 0; j < CHAN_BATCH; j++) { chantest_send(thd_off, chan_pair[1]); } /* printc("%d: pre-recv\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { - chantest_recv(thd_off, chan_pair[0]); - } + for (j = 0; j < CHAN_BATCH; j++) { chantest_recv(thd_off, chan_pair[0]); } } printc("SUCCESS! Counts (should be within %d of each other): ", NCHANTHDS * CHAN_BATCH); - for (i = 0; i < NCHANTHDS; i++) { - printc("\t%ld", cnts[i]); - } + for (i = 0; i < NCHANTHDS; i++) { printc("\t%ld", cnts[i]); } printc("\n"); - while (1) ; + while (1) + ; } void idle_thd(void *d) { printc("FAILURE: deadlock!\n"); - while (1) ; + while (1) + ; } void test_chan(void) { - int i; - struct sl_thd *idle; + int i; + struct sl_thd * idle; union sched_param_union idle_param = {.c = {.type = SCHEDP_PRIO, .value = 10}}; - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 7}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 8}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}} - }; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 7}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 8}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}}}; chans[0] = c0; chans[1] = c1; @@ -133,9 +136,7 @@ test_chan(void) chans[4] = c4; chans[5] = c0; - for (i = 0; i < NCHANTHDS; i++) { - crt_chan_init_test(chans[i]); - } + for (i = 0; i < NCHANTHDS; i++) { crt_chan_init_test(chans[i]); } printc("Create threads:\n"); for (i = 0; i < NCHANTHDS; i++) { @@ -147,14 +148,17 @@ test_chan(void) idle = sl_thd_alloc(idle_thd, NULL); printc("\tcreating IDLE %d at prio %d\n", sl_thd_thdid(idle), idle_param.c.value); sl_thd_param_set(idle, idle_param.v); - } #define LOCK_ITER 1000000 #define NLOCKTHDS 4 struct crt_lock lock; -struct sl_thd *lock_thds[NLOCKTHDS] = {NULL, }; -unsigned int progress[NLOCKTHDS] = {0, }; +struct sl_thd * lock_thds[NLOCKTHDS] = { + NULL, +}; +unsigned int progress[NLOCKTHDS] = { + 0, +}; volatile thdid_t holder; thdid_t @@ -196,25 +200,22 @@ lock_thd(void *d) for (i = 0; i < NLOCKTHDS; i++) { if (i == me) continue; - if (progress[i] < LOCK_ITER) { - sl_thd_yield(sl_thd_thdid(lock_thds[i])); - } + if (progress[i] < LOCK_ITER) { sl_thd_yield(sl_thd_thdid(lock_thds[i])); } } printc("SUCCESS!"); - while (1) ; + while (1) + ; } void test_lock(void) { - int i; - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}} - }; + int i; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}}}; crt_lock_init(&lock); @@ -227,13 +228,15 @@ test_lock(void) } #define NBLKTHDS 4 -struct sl_thd *blk_thds[NBLKTHDS] = {NULL, }; +struct sl_thd *blk_thds[NBLKTHDS] = { + NULL, +}; void blk_thd(void *d) { - struct crt_blkpt_checkpoint chkpt; - struct crt_blkpt blkpt; + struct crt_blkpt_checkpoint chkpt; + struct crt_blkpt blkpt; /* wake up all threads */ @@ -251,26 +254,21 @@ blk_thd(void *d) /* block and hopefully someone should wake us up */ crt_blkpt_wait(&blkpt, 0, &chkpt); - if(me == 0) - { - printc("SUCCESS"); - } + if (me == 0) { printc("SUCCESS"); } - while(1); + while (1) + ; } - void test_blkpt(void) { - int i; - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}} - }; + int i; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}}}; printc("Create threads:\n"); for (i = 0; i < NBLKTHDS; i++) { @@ -278,22 +276,21 @@ test_blkpt(void) printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[i]), sps[i].c.value); sl_thd_param_set(blk_thds[i], sps[i].v); } - } void cos_init(void) { struct cos_defcompinfo *defci = cos_defcompinfo_curr_get(); - ci = cos_compinfo_get(defci); + ci = cos_compinfo_get(defci); printc("Unit-test for the crt (sl)\n"); cos_meminfo_init(&(ci->mi), BOOT_MEM_KM_BASE, COS_MEM_KERN_PA_SZ, BOOT_CAPTBL_SELF_UNTYPED_PT); cos_defcompinfo_init(); sl_init(SL_MIN_PERIOD_US); - //test_lock(); -// test_chan(); + // test_lock(); + // test_chan(); test_blkpt(); From e128a22cd5643ba96caf44e1bb09646aa4b5be61 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Sat, 7 Mar 2020 16:19:05 -0500 Subject: [PATCH 19/30] formatting --- .../implementation/tests/crt_tests/crttests.c | 138 ++++++++++-------- 1 file changed, 74 insertions(+), 64 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index c86369b0f9..050dd698ba 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -14,8 +14,8 @@ struct cos_compinfo *ci; -#define CHAN_ITER 1000000 -#define NCHANTHDS 5 +#define CHAN_ITER 1000000 +#define NCHANTHDS 5 #define CHAN_BATCH 3 @@ -27,25 +27,16 @@ CRT_CHAN_STATIC_ALLOC(c4, int, 4); CRT_CHAN_TYPE_PROTOTYPES(test, int, 4); struct crt_chan *chans[NCHANTHDS + 1]; -struct sl_thd * chan_thds[NCHANTHDS] = { - NULL, -}; +struct sl_thd *chan_thds[NCHANTHDS] = {NULL, }; -typedef enum -{ - CHILLING = 0, - RECVING, - SENDING -} actions_t; +typedef enum { CHILLING = 0, RECVING, SENDING } actions_t; unsigned long status[NCHANTHDS]; -unsigned long cnts[NCHANTHDS] = { - 0, -}; +unsigned long cnts[NCHANTHDS] = {0, }; int chantest_is_deadlocked(void) { - int i; + int i; actions_t s = status[0]; /* Are all threads in the same blocked state? */ @@ -86,48 +77,54 @@ chantest_recv(int thd_off, struct crt_chan *c) void chan_thd(void *d) { - int thd_off = (int)d; + int thd_off = (int)d; struct crt_chan **chan_pair = &chans[thd_off]; - int recv; - int i; + int recv; + int i; for (i = 0; i < CHAN_ITER; i++) { int j; /* printc("%d: pre-send\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { chantest_send(thd_off, chan_pair[1]); } + for (j = 0; j < CHAN_BATCH; j++) { + chantest_send(thd_off, chan_pair[1]); + } /* printc("%d: pre-recv\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { chantest_recv(thd_off, chan_pair[0]); } + for (j = 0; j < CHAN_BATCH; j++) { + chantest_recv(thd_off, chan_pair[0]); + } } printc("SUCCESS! Counts (should be within %d of each other): ", NCHANTHDS * CHAN_BATCH); - for (i = 0; i < NCHANTHDS; i++) { printc("\t%ld", cnts[i]); } + for (i = 0; i < NCHANTHDS; i++) { + printc("\t%ld", cnts[i]); + } printc("\n"); - while (1) - ; + while (1) ; } void idle_thd(void *d) { printc("FAILURE: deadlock!\n"); - while (1) - ; + while (1) ; } void test_chan(void) { - int i; - struct sl_thd * idle; + int i; + struct sl_thd *idle; union sched_param_union idle_param = {.c = {.type = SCHEDP_PRIO, .value = 10}}; - union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 7}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 8}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}}}; + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 7}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 8}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}} + }; chans[0] = c0; chans[1] = c1; @@ -136,7 +133,9 @@ test_chan(void) chans[4] = c4; chans[5] = c0; - for (i = 0; i < NCHANTHDS; i++) { crt_chan_init_test(chans[i]); } + for (i = 0; i < NCHANTHDS; i++) { + crt_chan_init_test(chans[i]); + } printc("Create threads:\n"); for (i = 0; i < NCHANTHDS; i++) { @@ -148,17 +147,14 @@ test_chan(void) idle = sl_thd_alloc(idle_thd, NULL); printc("\tcreating IDLE %d at prio %d\n", sl_thd_thdid(idle), idle_param.c.value); sl_thd_param_set(idle, idle_param.v); + } #define LOCK_ITER 1000000 #define NLOCKTHDS 4 struct crt_lock lock; -struct sl_thd * lock_thds[NLOCKTHDS] = { - NULL, -}; -unsigned int progress[NLOCKTHDS] = { - 0, -}; +struct sl_thd *lock_thds[NLOCKTHDS] = {NULL, }; +unsigned int progress[NLOCKTHDS] = {0, }; volatile thdid_t holder; thdid_t @@ -200,22 +196,25 @@ lock_thd(void *d) for (i = 0; i < NLOCKTHDS; i++) { if (i == me) continue; - if (progress[i] < LOCK_ITER) { sl_thd_yield(sl_thd_thdid(lock_thds[i])); } + if (progress[i] < LOCK_ITER) { + sl_thd_yield(sl_thd_thdid(lock_thds[i])); + } } printc("SUCCESS!"); - while (1) - ; + while (1) ; } void test_lock(void) { - int i; - union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}}}; + int i; + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}} + }; crt_lock_init(&lock); @@ -228,16 +227,22 @@ test_lock(void) } #define NBLKTHDS 4 -struct sl_thd *blk_thds[NBLKTHDS] = { - NULL, -}; +struct sl_thd *blk_thds[NBLKTHDS] = {NULL, }; void blk_thd(void *d) { - struct crt_blkpt_checkpoint chkpt; - struct crt_blkpt blkpt; + struct crt_blkpt_checkpoint chkpt; + struct crt_blkpt blkpt; + int i, cnt, me = -1; + + for (i = 0; i < NLOCKTHDS; i++) { + if (sl_thd_thdid(blk_thds[i]) != cos_thdid()) continue; + + me = i; + } + assert(me != -1); /* wake up all threads */ crt_blkpt_trigger(&blkpt, 0); @@ -254,21 +259,25 @@ blk_thd(void *d) /* block and hopefully someone should wake us up */ crt_blkpt_wait(&blkpt, 0, &chkpt); - if (me == 0) { printc("SUCCESS"); } - - while (1) - ; + if(me == 0) + { + printc("SUCCESS"); + } + while(1); } + void test_blkpt(void) { - int i; - union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}}}; + int i; + union sched_param_union sps[] = { + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}} + }; printc("Create threads:\n"); for (i = 0; i < NBLKTHDS; i++) { @@ -276,21 +285,22 @@ test_blkpt(void) printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[i]), sps[i].c.value); sl_thd_param_set(blk_thds[i], sps[i].v); } + } void cos_init(void) { struct cos_defcompinfo *defci = cos_defcompinfo_curr_get(); - ci = cos_compinfo_get(defci); + ci = cos_compinfo_get(defci); printc("Unit-test for the crt (sl)\n"); cos_meminfo_init(&(ci->mi), BOOT_MEM_KM_BASE, COS_MEM_KERN_PA_SZ, BOOT_CAPTBL_SELF_UNTYPED_PT); cos_defcompinfo_init(); sl_init(SL_MIN_PERIOD_US); - // test_lock(); - // test_chan(); + //test_lock(); +// test_chan(); test_blkpt(); From e668f677a16c64e59de3d21c5324f4fc101f3bb8 Mon Sep 17 00:00:00 2001 From: Graham Schock Date: Sat, 7 Mar 2020 16:27:34 -0500 Subject: [PATCH 20/30] formatting --- .../implementation/tests/crt_tests/crttests.c | 129 +++++++++--------- 1 file changed, 63 insertions(+), 66 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 050dd698ba..1ad3cc55ca 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -14,8 +14,8 @@ struct cos_compinfo *ci; -#define CHAN_ITER 1000000 -#define NCHANTHDS 5 +#define CHAN_ITER 1000000 +#define NCHANTHDS 5 #define CHAN_BATCH 3 @@ -27,16 +27,25 @@ CRT_CHAN_STATIC_ALLOC(c4, int, 4); CRT_CHAN_TYPE_PROTOTYPES(test, int, 4); struct crt_chan *chans[NCHANTHDS + 1]; -struct sl_thd *chan_thds[NCHANTHDS] = {NULL, }; +struct sl_thd * chan_thds[NCHANTHDS] = { + NULL, +}; -typedef enum { CHILLING = 0, RECVING, SENDING } actions_t; +typedef enum +{ + CHILLING = 0, + RECVING, + SENDING +} actions_t; unsigned long status[NCHANTHDS]; -unsigned long cnts[NCHANTHDS] = {0, }; +unsigned long cnts[NCHANTHDS] = { + 0, +}; int chantest_is_deadlocked(void) { - int i; + int i; actions_t s = status[0]; /* Are all threads in the same blocked state? */ @@ -77,54 +86,48 @@ chantest_recv(int thd_off, struct crt_chan *c) void chan_thd(void *d) { - int thd_off = (int)d; + int thd_off = (int)d; struct crt_chan **chan_pair = &chans[thd_off]; - int recv; - int i; + int recv; + int i; for (i = 0; i < CHAN_ITER; i++) { int j; /* printc("%d: pre-send\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { - chantest_send(thd_off, chan_pair[1]); - } + for (j = 0; j < CHAN_BATCH; j++) { chantest_send(thd_off, chan_pair[1]); } /* printc("%d: pre-recv\n", cos_thdid()); */ - for (j = 0; j < CHAN_BATCH; j++) { - chantest_recv(thd_off, chan_pair[0]); - } + for (j = 0; j < CHAN_BATCH; j++) { chantest_recv(thd_off, chan_pair[0]); } } printc("SUCCESS! Counts (should be within %d of each other): ", NCHANTHDS * CHAN_BATCH); - for (i = 0; i < NCHANTHDS; i++) { - printc("\t%ld", cnts[i]); - } + for (i = 0; i < NCHANTHDS; i++) { printc("\t%ld", cnts[i]); } printc("\n"); - while (1) ; + while (1) + ; } void idle_thd(void *d) { printc("FAILURE: deadlock!\n"); - while (1) ; + while (1) + ; } void test_chan(void) { - int i; - struct sl_thd *idle; + int i; + struct sl_thd * idle; union sched_param_union idle_param = {.c = {.type = SCHEDP_PRIO, .value = 10}}; - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 7}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 8}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 5}} - }; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 7}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 8}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 5}}}; chans[0] = c0; chans[1] = c1; @@ -133,9 +136,7 @@ test_chan(void) chans[4] = c4; chans[5] = c0; - for (i = 0; i < NCHANTHDS; i++) { - crt_chan_init_test(chans[i]); - } + for (i = 0; i < NCHANTHDS; i++) { crt_chan_init_test(chans[i]); } printc("Create threads:\n"); for (i = 0; i < NCHANTHDS; i++) { @@ -147,14 +148,17 @@ test_chan(void) idle = sl_thd_alloc(idle_thd, NULL); printc("\tcreating IDLE %d at prio %d\n", sl_thd_thdid(idle), idle_param.c.value); sl_thd_param_set(idle, idle_param.v); - } #define LOCK_ITER 1000000 #define NLOCKTHDS 4 struct crt_lock lock; -struct sl_thd *lock_thds[NLOCKTHDS] = {NULL, }; -unsigned int progress[NLOCKTHDS] = {0, }; +struct sl_thd * lock_thds[NLOCKTHDS] = { + NULL, +}; +unsigned int progress[NLOCKTHDS] = { + 0, +}; volatile thdid_t holder; thdid_t @@ -196,25 +200,22 @@ lock_thd(void *d) for (i = 0; i < NLOCKTHDS; i++) { if (i == me) continue; - if (progress[i] < LOCK_ITER) { - sl_thd_yield(sl_thd_thdid(lock_thds[i])); - } + if (progress[i] < LOCK_ITER) { sl_thd_yield(sl_thd_thdid(lock_thds[i])); } } printc("SUCCESS!"); - while (1) ; + while (1) + ; } void test_lock(void) { - int i; - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}} - }; + int i; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}}}; crt_lock_init(&lock); @@ -227,13 +228,15 @@ test_lock(void) } #define NBLKTHDS 4 -struct sl_thd *blk_thds[NBLKTHDS] = {NULL, }; +struct sl_thd *blk_thds[NBLKTHDS] = { + NULL, +}; void blk_thd(void *d) { - struct crt_blkpt_checkpoint chkpt; - struct crt_blkpt blkpt; + struct crt_blkpt_checkpoint chkpt; + struct crt_blkpt blkpt; int i, cnt, me = -1; @@ -259,25 +262,20 @@ blk_thd(void *d) /* block and hopefully someone should wake us up */ crt_blkpt_wait(&blkpt, 0, &chkpt); - if(me == 0) - { - printc("SUCCESS"); - } - while(1); + if (me == 0) printc("SUCCESS"); + while (1) + ; } - void test_blkpt(void) { - int i; - union sched_param_union sps[] = { - {.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}} - }; + int i; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}}}; printc("Create threads:\n"); for (i = 0; i < NBLKTHDS; i++) { @@ -285,22 +283,21 @@ test_blkpt(void) printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[i]), sps[i].c.value); sl_thd_param_set(blk_thds[i], sps[i].v); } - } void cos_init(void) { struct cos_defcompinfo *defci = cos_defcompinfo_curr_get(); - ci = cos_compinfo_get(defci); + ci = cos_compinfo_get(defci); printc("Unit-test for the crt (sl)\n"); cos_meminfo_init(&(ci->mi), BOOT_MEM_KM_BASE, COS_MEM_KERN_PA_SZ, BOOT_CAPTBL_SELF_UNTYPED_PT); cos_defcompinfo_init(); sl_init(SL_MIN_PERIOD_US); - //test_lock(); -// test_chan(); + // test_lock(); + // test_chan(); test_blkpt(); From 97855af661d276db36a9847cfe92add80fe9ff86 Mon Sep 17 00:00:00 2001 From: gschock Date: Thu, 12 Mar 2020 08:47:21 -0400 Subject: [PATCH 21/30] update crt_lock --- src/components/include/crt_lock.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/include/crt_lock.h b/src/components/include/crt_lock.h index d2cba0f90c..40aa7c1510 100644 --- a/src/components/include/crt_lock.h +++ b/src/components/include/crt_lock.h @@ -31,13 +31,13 @@ crt_sem_up(struct crt_sem *s) while (1) { crt_blkpt_checkpoint(&s->blkpt, &chkpt); - if (s->count < s->max_threads) { return; } + if (s->count < s->max_threads) return; crt_blkpt_wait (&s->blkpt, 0, &chkpt); } } static inline void -crt_sem_alloc(struct crt_sem *s, int size) +crt_sem_init(struct crt_sem *s, int size) { s->max_threads = size; s->count = 0; From 3d3af596d66885cb002766f72d32f407ba0c3384 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Tue, 24 Mar 2020 15:22:34 -0400 Subject: [PATCH 22/30] added single thread crt tests --- .../implementation/tests/crt_tests/crttests.c | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 1ad3cc55ca..4b8222cb2c 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -232,6 +232,8 @@ struct sl_thd *blk_thds[NBLKTHDS] = { NULL, }; +int progress_shared = 0; + void blk_thd(void *d) { @@ -240,29 +242,30 @@ blk_thd(void *d) int i, cnt, me = -1; - for (i = 0; i < NLOCKTHDS; i++) { + for (i = 0; i < 1; i++) { if (sl_thd_thdid(blk_thds[i]) != cos_thdid()) continue; me = i; } assert(me != -1); - /* wake up all threads */ - crt_blkpt_trigger(&blkpt, 0); - + + /* set up a checkoint */ crt_blkpt_checkpoint(&blkpt, &chkpt); - /* prempt thread */ - sl_thd_yield(sl_thd_thdid(blk_thds[1])); + crt_blkpt_trigger(&blkpt, 0); - /* go back to original thread */ - sl_thd_yield(sl_thd_thdid(blk_thds[0])); + crt_blkpt_checkpoint(&blkpt, &chkpt); - /* block and hopefully someone should wake us up */ - crt_blkpt_wait(&blkpt, 0, &chkpt); + if(blkpt.epoch_blocked != chkpt.epoch_blocked) + { + printc("FAILURE"); + } + else{ + printc("SUCCESS"); + } - if (me == 0) printc("SUCCESS"); while (1) ; } @@ -272,13 +275,10 @@ void test_blkpt(void) { int i; - union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}, - {.c = {.type = SCHEDP_PRIO, .value = 7}}}; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}}; printc("Create threads:\n"); - for (i = 0; i < NBLKTHDS; i++) { + for (i = 0; i < 1; i++) { blk_thds[i] = sl_thd_alloc(blk_thd, NULL); printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[i]), sps[i].c.value); sl_thd_param_set(blk_thds[i], sps[i].v); From cda34241c1ee4e05b598c8e375b3f6817313747f Mon Sep 17 00:00:00 2001 From: grahamschock Date: Tue, 24 Mar 2020 15:25:01 -0400 Subject: [PATCH 23/30] added some comments --- src/components/implementation/tests/crt_tests/crttests.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 4b8222cb2c..090602ad89 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -258,6 +258,7 @@ blk_thd(void *d) crt_blkpt_checkpoint(&blkpt, &chkpt); + /* there is no thread to preempt us so these should be the same */ if(blkpt.epoch_blocked != chkpt.epoch_blocked) { printc("FAILURE"); From 0b43cdb3cbab8f68de50cc9148d925024c6be305 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Tue, 24 Mar 2020 16:14:09 -0400 Subject: [PATCH 24/30] formatting and removing unessecary loops --- .../implementation/tests/crt_tests/crttests.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 090602ad89..67718e2447 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -248,8 +248,6 @@ blk_thd(void *d) me = i; } assert(me != -1); - - /* set up a checkoint */ crt_blkpt_checkpoint(&blkpt, &chkpt); @@ -277,13 +275,10 @@ test_blkpt(void) { int i; union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}}; - - printc("Create threads:\n"); - for (i = 0; i < 1; i++) { - blk_thds[i] = sl_thd_alloc(blk_thd, NULL); - printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[i]), sps[i].c.value); - sl_thd_param_set(blk_thds[i], sps[i].v); - } + printc("Create thread:\n"); + blk_thds[0] = sl_thd_alloc(blk_thd, NULL); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[0]), sps[0].c.value); + sl_thd_param_set(blk_thds[0], sps[0].v); } void From d560d9e8280a9d0dbffe0728754a779a16db4f10 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Wed, 25 Mar 2020 21:49:20 -0400 Subject: [PATCH 25/30] added test 2 --- .../implementation/tests/crt_tests/crttests.c | 95 +++++++++++++++---- 1 file changed, 75 insertions(+), 20 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 67718e2447..30c038bd4f 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -227,60 +227,114 @@ test_lock(void) } } -#define NBLKTHDS 4 -struct sl_thd *blk_thds[NBLKTHDS] = { +struct sl_thd *blk_thds1[1] = { NULL, }; +struct sl_thd *blk_thds2[2] = { + NULL, +}; + + int progress_shared = 0; +struct crt_blkpt blkpt_test_1; +struct crt_blkpt blkpt_test_2; + void -blk_thd(void *d) +blk_thd1(void *d) { - struct crt_blkpt_checkpoint chkpt; - struct crt_blkpt blkpt; + int i, cnt, me = -1; for (i = 0; i < 1; i++) { - if (sl_thd_thdid(blk_thds[i]) != cos_thdid()) continue; + if (sl_thd_thdid(blk_thds1[i]) != cos_thdid()) continue; me = i; } assert(me != -1); + + struct crt_blkpt_checkpoint chkpt; /* set up a checkoint */ - crt_blkpt_checkpoint(&blkpt, &chkpt); + crt_blkpt_checkpoint(&blkpt_test_1, &chkpt); - crt_blkpt_trigger(&blkpt, 0); - - crt_blkpt_checkpoint(&blkpt, &chkpt); + /* wake up all threads */ + crt_blkpt_trigger(&blkpt_test_1, 0); /* there is no thread to preempt us so these should be the same */ - if(blkpt.epoch_blocked != chkpt.epoch_blocked) - { + if(blkpt_test_1.epoch_blocked != chkpt.epoch_blocked) { printc("FAILURE"); + while(1) + ; } - else{ - printc("SUCCESS"); - } + printc("SUCCESS!"); while (1) ; } +void +blk_thd2(void *d) +{ + struct crt_blkpt_checkpoint chkpt; + + /* set up a checkoint */ + crt_blkpt_checkpoint(&blkpt_test_2, &chkpt); + + crt_blkpt_trigger(&blkpt_test_2, 0); + crt_blkpt_wait(&blkpt_test_2, 0, &chkpt); + + progress_shared++; + + while(1); +} void -test_blkpt(void) +blk_thd3(void *d) +{ + if(progress_shared == 0) + { + printc("Failure"); + while(1); + } + printc("Success!"); + while(1); +} + +void +test_blkpt1(void) { int i; union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 5}}}; + crt_blkpt_init(&blkpt_test_1); + printc("Create thread:\n"); + blk_thds1[0] = sl_thd_alloc(blk_thd1, NULL); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds1[0]), sps[0].c.value); + sl_thd_param_set(blk_thds1[0], sps[0].v); + + +} + +void +test_blkpt2(void) +{ + int i; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 7}}, + {.c = {.type = SCHEDP_PRIO, .value = 6}}}; + crt_blkpt_init(&blkpt_test_2); printc("Create thread:\n"); - blk_thds[0] = sl_thd_alloc(blk_thd, NULL); - printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds[0]), sps[0].c.value); - sl_thd_param_set(blk_thds[0], sps[0].v); + blk_thds2[0] = sl_thd_alloc(blk_thd2, NULL); + blk_thds2[1] = sl_thd_alloc(blk_thd3, NULL); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds2[0]), sps[0].c.value); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds2[1]), sps[1].c.value); + sl_thd_param_set(blk_thds2[0], sps[0].v); + sl_thd_param_set(blk_thds2[1], sps[1].v); + } + void cos_init(void) { @@ -295,7 +349,8 @@ cos_init(void) // test_lock(); // test_chan(); - test_blkpt(); + // test_blkpt1(); + test_blkpt2(); printc("Running benchmark...\n"); sl_sched_loop_nonblock(); From 2d1376b21b28045ceb18167ef0db3bfb269c4eb1 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Fri, 27 Mar 2020 12:02:13 -0400 Subject: [PATCH 26/30] finished blkpt_test3 --- .../implementation/tests/crt_tests/crttests.c | 79 +++++++++++++++++-- 1 file changed, 71 insertions(+), 8 deletions(-) diff --git a/src/components/implementation/tests/crt_tests/crttests.c b/src/components/implementation/tests/crt_tests/crttests.c index 30c038bd4f..ab735a62de 100644 --- a/src/components/implementation/tests/crt_tests/crttests.c +++ b/src/components/implementation/tests/crt_tests/crttests.c @@ -235,11 +235,18 @@ struct sl_thd *blk_thds2[2] = { NULL, }; +struct sl_thd *blk_thds3[2] = { + NULL, +}; + + int progress_shared = 0; struct crt_blkpt blkpt_test_1; struct crt_blkpt blkpt_test_2; +struct crt_blkpt blkpt_test_3; + void blk_thd1(void *d) @@ -247,7 +254,7 @@ blk_thd1(void *d) int i, cnt, me = -1; - + //put this into function for (i = 0; i < 1; i++) { if (sl_thd_thdid(blk_thds1[i]) != cos_thdid()) continue; @@ -263,6 +270,8 @@ blk_thd1(void *d) /* wake up all threads */ crt_blkpt_trigger(&blkpt_test_1, 0); + //check API behavior in code + /* there is no thread to preempt us so these should be the same */ if(blkpt_test_1.epoch_blocked != chkpt.epoch_blocked) { printc("FAILURE"); @@ -285,24 +294,55 @@ blk_thd2(void *d) crt_blkpt_trigger(&blkpt_test_2, 0); crt_blkpt_wait(&blkpt_test_2, 0, &chkpt); - + progress_shared++; + sl_thd_yield(sl_thd_thdid(blk_thds2[1])); + while(1); } void blk_thd3(void *d) { - if(progress_shared == 0) - { + if(progress_shared == 0) { printc("Failure"); while(1); } printc("Success!"); while(1); } - + +void +blk_thd4(void *d) +{ + struct crt_blkpt_checkpoint chkpt; + + crt_blkpt_checkpoint(&blkpt_test_3, &chkpt); + + crt_blkpt_wait(&blkpt_test_3, 0, &chkpt); + + progress_shared++; + + sl_thd_yield(sl_thd_thdid(blk_thds3[1])); + + while(1); + +} + +void +blk_thd5(void *d) +{ + if(progress_shared == 0) { + printc("Success!"); + while(1); + } + printc("Failure"); + while(1); +} + + + void test_blkpt1(void) { @@ -321,8 +361,10 @@ void test_blkpt2(void) { int i; - union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 7}}, - {.c = {.type = SCHEDP_PRIO, .value = 6}}}; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}}}; + + progress_shared = 0; crt_blkpt_init(&blkpt_test_2); printc("Create thread:\n"); blk_thds2[0] = sl_thd_alloc(blk_thd2, NULL); @@ -334,6 +376,26 @@ test_blkpt2(void) } +void +test_blkpt3(void) +{ + int i; + union sched_param_union sps[] = {{.c = {.type = SCHEDP_PRIO, .value = 6}}, + {.c = {.type = SCHEDP_PRIO, .value = 7}}}; + + progress_shared = 0; + crt_blkpt_init(&blkpt_test_3); + printc("Create thread:\n"); + blk_thds3[0] = sl_thd_alloc(blk_thd4, NULL); + blk_thds3[1] = sl_thd_alloc(blk_thd5, NULL); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds3[0]), sps[0].c.value); + printc("\tcreating thread %d at prio %d\n", sl_thd_thdid(blk_thds3[1]), sps[1].c.value); + sl_thd_param_set(blk_thds3[0], sps[0].v); + sl_thd_param_set(blk_thds3[1], sps[1].v); + +} + + void cos_init(void) @@ -350,7 +412,8 @@ cos_init(void) // test_chan(); // test_blkpt1(); - test_blkpt2(); + // test_blkpt2(); + test_blkpt3(); printc("Running benchmark...\n"); sl_sched_loop_nonblock(); From 90de555daab2c05c5d5cb108b46eac67aab8e707 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Fri, 3 Apr 2020 13:02:35 -0400 Subject: [PATCH 27/30] trying to fix trigger when no blocked thread --- src/components/include/crt_blkpt.h | 20 +++++++++++++++++--- src/components/include/crt_lock.h | 7 +++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/components/include/crt_blkpt.h b/src/components/include/crt_blkpt.h index d647dc50d9..c8555f621c 100644 --- a/src/components/include/crt_blkpt.h +++ b/src/components/include/crt_blkpt.h @@ -128,6 +128,7 @@ struct crt_blkpt_checkpoint { typedef enum { CRT_BLKPT_UNIPROC = 1, /* are the event operations only called on a single core? */ CRT_BLKPT_CRIT_SECT = 2, /* is only one thread ever going to trigger at a time? */ + CRT_BLKPT_WAKE_ALL = 4 } crt_blkpt_flags_t; #define CRT_BLKPT_EPOCH_BLKED_BITS (sizeof(sched_blkpt_epoch_t) * 8) @@ -158,6 +159,7 @@ crt_blkpt_teardown(struct crt_blkpt *blkpt) return sched_blkpt_free(blkpt->id); } +//returns IF updated chkpt and unmasks block value /* Internal APIs that must be inlined to remove the branches */ static inline int __crt_blkpt_atomic_trigger(sched_blkpt_epoch_t *ec, sched_blkpt_epoch_t chkpt, crt_blkpt_flags_t flags) @@ -229,11 +231,18 @@ crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) * as constants. That way they will be inlined the conditions * in the *_atomic_* function will be removed. */ - sched_blkpt_epoch_t saved = ps_load(&blkpt->epoch_blocked); + + sched_blkpt_epoch_t saved = ps_load(&blkpt->epoch_blocked); /* The optimization: don't increment events if noone's listening */ - if (likely(!CRT_BLKPT_BLKED(saved))) return; + while (likely(!CRT_BLKPT_BLKED(saved))) { + + saved = ps_load(&blkpt->epoch_blocked); + if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) continue; + return; + } + /* slow(er) path for when we have blocked threads */ if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) { /* @@ -250,7 +259,12 @@ crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) * = max(epoch, ...) (for some wraparound-aware version of * max). */ - sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 0); + if (flags & CRT_BLKPT_WAKE_ALL) { + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 0); + } else { + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 1); + } + } /* Wake only a single, specified thread (tracked manually in the data-structure) */ diff --git a/src/components/include/crt_lock.h b/src/components/include/crt_lock.h index 40aa7c1510..d46d45f9a2 100644 --- a/src/components/include/crt_lock.h +++ b/src/components/include/crt_lock.h @@ -53,6 +53,13 @@ crt_sem_down(struct crt_sem *s) crt_blkpt_trigger(&s->blkpt, 0); } +/* static inline void */ +/* crt_mutex_init(struct crt_mutex *m) */ +/* { */ + +/* } */ + + static inline int crt_lock_init(struct crt_lock *l) { From 1e0f9c44941695affa942f791b9c41f3f92b8024 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Fri, 3 Apr 2020 13:04:48 -0400 Subject: [PATCH 28/30] formatting --- src/components/include/crt_blkpt.h | 56 ++++++++++++++---------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/components/include/crt_blkpt.h b/src/components/include/crt_blkpt.h index c8555f621c..17a299a576 100644 --- a/src/components/include/crt_blkpt.h +++ b/src/components/include/crt_blkpt.h @@ -116,7 +116,7 @@ */ struct crt_blkpt { - sched_blkpt_id_t id; + sched_blkpt_id_t id; /* most significant bit specifies blocked thds */ sched_blkpt_epoch_t epoch_blocked; }; @@ -125,16 +125,17 @@ struct crt_blkpt_checkpoint { sched_blkpt_epoch_t epoch_blocked; }; -typedef enum { - CRT_BLKPT_UNIPROC = 1, /* are the event operations only called on a single core? */ - CRT_BLKPT_CRIT_SECT = 2, /* is only one thread ever going to trigger at a time? */ - CRT_BLKPT_WAKE_ALL = 4 +typedef enum +{ + CRT_BLKPT_UNIPROC = 1, /* are the event operations only called on a single core? */ + CRT_BLKPT_CRIT_SECT = 2, /* is only one thread ever going to trigger at a time? */ + CRT_BLKPT_WAKE_ALL = 4 } crt_blkpt_flags_t; #define CRT_BLKPT_EPOCH_BLKED_BITS (sizeof(sched_blkpt_epoch_t) * 8) -#define CRT_BLKPT_BLKED_MASK (1 << (CRT_BLKPT_EPOCH_BLKED_BITS - 2)) -#define CRT_BLKPT_BLKED(e) ((e) & CRT_BLKPT_BLKED_MASK) -#define CRT_BLKPT_EPOCH(e) ((e) & ~CRT_BLKPT_BLKED_MASK) +#define CRT_BLKPT_BLKED_MASK (1 << (CRT_BLKPT_EPOCH_BLKED_BITS - 2)) +#define CRT_BLKPT_BLKED(e) ((e)&CRT_BLKPT_BLKED_MASK) +#define CRT_BLKPT_EPOCH(e) ((e) & ~CRT_BLKPT_BLKED_MASK) /* Return != 0 on failure: no ids to allocate */ static inline int @@ -145,10 +146,7 @@ crt_blkpt_init(struct crt_blkpt *blkpt) id = sched_blkpt_alloc(); if (id == SCHED_BLKPT_NULL) return -1; - *blkpt = (struct crt_blkpt){ - .id = id, - .epoch_blocked = 0 - }; + *blkpt = (struct crt_blkpt){.id = id, .epoch_blocked = 0}; return 0; } @@ -159,7 +157,7 @@ crt_blkpt_teardown(struct crt_blkpt *blkpt) return sched_blkpt_free(blkpt->id); } -//returns IF updated chkpt and unmasks block value +// returns IF updated chkpt and unmasks block value /* Internal APIs that must be inlined to remove the branches */ static inline int __crt_blkpt_atomic_trigger(sched_blkpt_epoch_t *ec, sched_blkpt_epoch_t chkpt, crt_blkpt_flags_t flags) @@ -232,17 +230,14 @@ crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) * in the *_atomic_* function will be removed. */ - sched_blkpt_epoch_t saved = ps_load(&blkpt->epoch_blocked); + sched_blkpt_epoch_t saved = ps_load(&blkpt->epoch_blocked); - /* The optimization: don't increment events if noone's listening */ while (likely(!CRT_BLKPT_BLKED(saved))) { - - saved = ps_load(&blkpt->epoch_blocked); - if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) continue; - return; + saved = ps_load(&blkpt->epoch_blocked); + if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) continue; + return; + } - } - /* slow(er) path for when we have blocked threads */ if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) { /* @@ -260,11 +255,10 @@ crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) * max). */ if (flags & CRT_BLKPT_WAKE_ALL) { - sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 0); - } else { - sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 1); - } - + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 0); + } else { + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 1); + } } /* Wake only a single, specified thread (tracked manually in the data-structure) */ @@ -295,11 +289,12 @@ crt_blkpt_wait(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, struct crt_blkp * updated, so return and try accessing the data-structure * again. */ - if (!CRT_BLKPT_BLKED(chkpt->epoch_blocked) && - !__crt_blkpt_atomic_wait(&blkpt->epoch_blocked, chkpt->epoch_blocked, flags)) return; + if (!CRT_BLKPT_BLKED(chkpt->epoch_blocked) + && !__crt_blkpt_atomic_wait(&blkpt->epoch_blocked, chkpt->epoch_blocked, flags)) + return; if (unlikely(sched_blkpt_block(blkpt->id, CRT_BLKPT_EPOCH(chkpt->epoch_blocked), 0))) { - BUG(); /* we are using a blkpt id that doesn't exist! */ + BUG(); /* we are using a blkpt id that doesn't exist! */ } } @@ -307,6 +302,7 @@ crt_blkpt_wait(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, struct crt_blkp * Create an execution dependency on the specified thread for, * e.g. priority inheritance. */ -/* void crt_blkpt_wait_dep(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, struct crt_blkpt_checkpoint *chkpt, cos_thdid_t thdid); */ +/* void crt_blkpt_wait_dep(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags, struct crt_blkpt_checkpoint *chkpt, + * cos_thdid_t thdid); */ #endif /* CRT_BLKPT_H */ From a6bfe0a5f981bcac1a53763a98009ffe53713f10 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Sun, 12 Apr 2020 19:16:50 -0400 Subject: [PATCH 29/30] crt_blkpt bug --- src/components/include/crt_blkpt.h | 55 +++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/components/include/crt_blkpt.h b/src/components/include/crt_blkpt.h index 17a299a576..d775a37876 100644 --- a/src/components/include/crt_blkpt.h +++ b/src/components/include/crt_blkpt.h @@ -229,36 +229,57 @@ crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) * as constants. That way they will be inlined the conditions * in the *_atomic_* function will be removed. */ + int wake_single; sched_blkpt_epoch_t saved = ps_load(&blkpt->epoch_blocked); + + /* + 1. do trigger and update epoch see if blocked threads + 2. if blocked threads proceed + 3. if no blocked threads return + 4, + */ + + + do { + saved = ps_load(&blkpt->epoch_blocked); + } while (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)); + if(likely(!CRT_BLKPT_BLKED(saved))) return; + + + + + + /* while (likely(!CRT_BLKPT_BLKED(saved))) { - saved = ps_load(&blkpt->epoch_blocked); - if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) continue; - return; + saved = ps_load(&blkpt->epoch_blocked); + if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) continue; + return; } - /* slow(er) path for when we have blocked threads */ + slow(er) path for when we have blocked threads if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) { - /* - * Race here between triggering threads. In this case, - * someone else already incremented the epoch and - * unblocked the threads. Yeah, helping algorithms! - */ - return; + * + * Race here between triggering threads. In this case, + * someone else already incremented the epoch and + * unblocked the threads. Yeah, helping algorithms! + * + return; } - /* + * * Note that there is a race here. Multiple threads triggering * events might pass different epochs down to the next * level. This is OK as the next level always takes the epoch * = max(epoch, ...) (for some wraparound-aware version of * max). - */ - if (flags & CRT_BLKPT_WAKE_ALL) { - sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 0); - } else { - sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), 1); - } + * + */ + wake_single = (flags & CRT_BLKPT_WAKE_ALL) == 0; + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), wake_single); + + + } /* Wake only a single, specified thread (tracked manually in the data-structure) */ From 92552f0b1b9f60dab1af25e8b420cc92b2a6dad4 Mon Sep 17 00:00:00 2001 From: grahamschock Date: Mon, 20 Apr 2020 13:39:21 -0400 Subject: [PATCH 30/30] fixed formatting --- .gitmodules | 3 +++ src/components/include/crt_blkpt.h | 42 +++++------------------------- src/components/lib/linux | 1 + 3 files changed, 10 insertions(+), 36 deletions(-) create mode 160000 src/components/lib/linux diff --git a/.gitmodules b/.gitmodules index 0f50366a4d..fea766a4e4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "src/components/lib/ck/ck"] path = src/components/lib/ck/ck url = https://github.com/gwsystems/ck.git +[submodule "src/components/lib/linux"] + path = src/components/lib/linux + url = https://github.com/lkl/linux.git diff --git a/src/components/include/crt_blkpt.h b/src/components/include/crt_blkpt.h index d775a37876..c29e4943ee 100644 --- a/src/components/include/crt_blkpt.h +++ b/src/components/include/crt_blkpt.h @@ -242,44 +242,14 @@ crt_blkpt_trigger(struct crt_blkpt *blkpt, crt_blkpt_flags_t flags) */ - do { - saved = ps_load(&blkpt->epoch_blocked); - } while (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)); - if(likely(!CRT_BLKPT_BLKED(saved))) return; + do { + saved = ps_load(&blkpt->epoch_blocked); + } while (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)); + if (likely(!CRT_BLKPT_BLKED(saved))) return; - - - - /* - while (likely(!CRT_BLKPT_BLKED(saved))) { - saved = ps_load(&blkpt->epoch_blocked); - if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) continue; - return; - } - - slow(er) path for when we have blocked threads - if (!__crt_blkpt_atomic_trigger(&blkpt->epoch_blocked, saved, flags)) { - * - * Race here between triggering threads. In this case, - * someone else already incremented the epoch and - * unblocked the threads. Yeah, helping algorithms! - * - return; - } - * - * Note that there is a race here. Multiple threads triggering - * events might pass different epochs down to the next - * level. This is OK as the next level always takes the epoch - * = max(epoch, ...) (for some wraparound-aware version of - * max). - * - */ - wake_single = (flags & CRT_BLKPT_WAKE_ALL) == 0; - sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), wake_single); - - - + wake_single = (flags & CRT_BLKPT_WAKE_ALL) == 0; + sched_blkpt_trigger(blkpt->id, CRT_BLKPT_EPOCH(saved + 1), wake_single); } /* Wake only a single, specified thread (tracked manually in the data-structure) */ diff --git a/src/components/lib/linux b/src/components/lib/linux new file mode 160000 index 0000000000..8a1fc6cf60 --- /dev/null +++ b/src/components/lib/linux @@ -0,0 +1 @@ +Subproject commit 8a1fc6cf60d853e9abf724a3ed27d5680fb5807f