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>