Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Aug 2018 15:37:27 +0200
From:      Sebastian Huber <sebastian.huber@embedded-brains.de>
To:        FreeBSD <freebsd-hackers@freebsd.org>
Subject:   Re: epoch(9) background information?
Message-ID:  <b75359f8-f05e-b2c8-0b28-0c3e03bfa3fd@embedded-brains.de>
In-Reply-To: <db397431-2c4c-64de-634a-20f38ce6a60e@embedded-brains.de>
References:  <db397431-2c4c-64de-634a-20f38ce6a60e@embedded-brains.de>

next in thread | previous in thread | raw e-mail | index | archive | help
Hello,

I try currently to understand the epoch implementation in FreeBSD to=20
implement the API in RTEMS.

If I understood epoch_wait() correctly, then this function just busy=20
waits until all conditions are satisfied. This is all right, since all=20
other participants operate with thread dispatching disabled, so the time=20
can be only influenced by interrupts and actual work.

I have some questions to epoch_block_handler_preempt(). The caller of=20
epoch_wait_prempt() seems to depend on threads which are currently=20
blocked, so busy waiting is not a good idea. Some questions to the code:

/*
 =C2=A0* epoch_block_handler_preempt is a callback from the ck code when=20
another thread is
 =C2=A0* currently in an epoch section.
 =C2=A0*/
static void
epoch_block_handler_preempt(struct ck_epoch *global __unused,=20
ck_epoch_record_t *cr,
 =C2=A0=C2=A0=C2=A0 void *arg __unused)
{
 =C2=A0=C2=A0=C2=A0 epoch_record_t record;
 =C2=A0=C2=A0=C2=A0 struct thread *td, *owner, *curwaittd;
 =C2=A0=C2=A0=C2=A0 struct epoch_thread *tdwait;
 =C2=A0=C2=A0=C2=A0 struct turnstile *ts;
 =C2=A0=C2=A0=C2=A0 struct lock_object *lock;
 =C2=A0=C2=A0=C2=A0 int spincount, gen;
 =C2=A0=C2=A0=C2=A0 int locksheld __unused;

 =C2=A0=C2=A0=C2=A0 record =3D __containerof(cr, struct epoch_record, er_=
record);
 =C2=A0=C2=A0=C2=A0 td =3D curthread;
 =C2=A0=C2=A0=C2=A0 locksheld =3D td->td_locks;
 =C2=A0=C2=A0=C2=A0 spincount =3D 0;
 =C2=A0=C2=A0=C2=A0 counter_u64_add(block_count, 1);
 =C2=A0=C2=A0=C2=A0 /*
 =C2=A0=C2=A0=C2=A0 =C2=A0* We lost a race and there's no longer any thre=
ads
 =C2=A0=C2=A0=C2=A0 =C2=A0* on the CPU in an epoch section.
 =C2=A0=C2=A0=C2=A0 =C2=A0*/
 =C2=A0=C2=A0=C2=A0 if (TAILQ_EMPTY(&record->er_tdlist))
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 return;

 =C2=A0=C2=A0=C2=A0 if (record->er_cpuid !=3D curcpu) {
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 ...

### this seems clear

 =C2=A0=C2=A0=C2=A0 }
 =C2=A0=C2=A0=C2=A0 /*
 =C2=A0=C2=A0=C2=A0 =C2=A0* Try to find a thread in an epoch section on t=
his CPU
 =C2=A0=C2=A0=C2=A0 =C2=A0* waiting on a turnstile. Otherwise find the lo=
west
 =C2=A0=C2=A0=C2=A0 =C2=A0* priority thread (highest prio value) and drop=
 our priority
 =C2=A0=C2=A0=C2=A0 =C2=A0* to match to allow it to run.
 =C2=A0=C2=A0=C2=A0 =C2=A0*/
 =C2=A0=C2=A0=C2=A0 TAILQ_FOREACH(tdwait, &record->er_tdlist, et_link) {
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 /*
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0* Propagate our priority to =
any other waiters to prevent us
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0* from starving them. They w=
ill have their original priority
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0* restore on exit from epoch=
_wait().
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0*/
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 curwaittd =3D tdwait->et_td;
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 if (!TD_IS_INHIBITED(curwaittd) &&=
 curwaittd->td_priority >=20
td->td_priority) {
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 critical_enter(=
);
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 thread_unlock(t=
d);
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 thread_lock(cur=
waittd);

### could we accidentally lower the priority here?

 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 sched_prio(curw=
aittd, td->td_priority);
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 thread_unlock(c=
urwaittd);
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 thread_lock(td)=
;
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 critical_exit()=
;
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 if (TD_IS_INHIBITED(curwaittd) && =
TD_ON_LOCK(curwaittd) &&
 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 ((ts =3D curwai=
ttd->td_blocked) !=3D NULL)) {
 =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ...

### is this some sort of condition variable which wakes us up together=20
with the waiting thread?

 =C2=A0=C2=A0=C2=A0 =C2=A0=C2=A0=C2=A0 }
 =C2=A0=C2=A0=C2=A0 }

### is this a yield operation, e.g. in case we still the highest=20
priority thread, then we run immediately again?

 =C2=A0=C2=A0=C2=A0 /*
 =C2=A0=C2=A0=C2=A0 =C2=A0* We didn't find any threads actually blocked o=
n a lock
 =C2=A0=C2=A0=C2=A0 =C2=A0* so we have nothing to do except context switc=
h away.
 =C2=A0=C2=A0=C2=A0 =C2=A0*/
 =C2=A0=C2=A0=C2=A0 counter_u64_add(switch_count, 1);
 =C2=A0=C2=A0=C2=A0 mi_switch(SW_VOL | SWT_RELINQUISH, NULL);

 =C2=A0=C2=A0=C2=A0 /*
 =C2=A0=C2=A0=C2=A0 =C2=A0* Release the thread lock while yielding to
 =C2=A0=C2=A0=C2=A0 =C2=A0* allow other threads to acquire the lock
 =C2=A0=C2=A0=C2=A0 =C2=A0* pointed to by TDQ_LOCKPTR(td). Else a
 =C2=A0=C2=A0=C2=A0 =C2=A0* deadlock like situation might happen. (HPS)
 =C2=A0=C2=A0=C2=A0 =C2=A0*/
 =C2=A0=C2=A0=C2=A0 thread_unlock(td);
 =C2=A0=C2=A0=C2=A0 thread_lock(td);
}

--=20
Sebastian Huber, embedded brains GmbH

Address : Dornierstr. 4, D-82178 Puchheim, Germany
Phone   : +49 89 189 47 41-16
Fax     : +49 89 189 47 41-09
E-Mail  : sebastian.huber@embedded-brains.de
PGP     : Public key available on request.

Diese Nachricht ist keine gesch=C3=A4ftliche Mitteilung im Sinne des EHUG=
.




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?b75359f8-f05e-b2c8-0b28-0c3e03bfa3fd>