Page MenuHomeFreeBSD

sound: track kqueue low watermark per-knote for mmaped channels
Needs ReviewPublic

Authored by meka_tilda.center on Wed, Jun 24, 10:23 PM.
Tags
None
Referenced Files
Unknown Object (File)
Fri, Jun 26, 3:48 PM
Unknown Object (File)
Fri, Jun 26, 10:21 AM
Unknown Object (File)
Thu, Jun 25, 7:24 PM
Unknown Object (File)
Wed, Jun 24, 11:45 PM
Subscribers

Details

Reviewers
christos
markj
kib
Summary

Use kn->kn_sdata to track the last bs->total value for each knote attached to an mmaped channel. An event is delivered only when the total byte counter has advanced by at least c->lw since the last delivery. After delivery kn_sdata is updated to the current total.

Each knote tracks its own watermark independently, so multiple knotes attached to the same mmaped channel all receive events correctly.

Non-mmap channels keep the existing level-triggered behavior via chn_polltrigger().

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

Why the title says that the fix is for 'mapped' devices? What specifically is different there?

Also, what if there is more than one knote attached?

meka_tilda.center edited the summary of this revision. (Show Details)

I was mislead by looking at select/poll and totally forgot that knotes persist in the kernel once registered. @kib thank you for pointing it out. As for title, I forgot to include "kqueue" in it to make it more obvious.

meka_tilda.center retitled this revision from sound: fix low watermark for mmaped devices to sound: track kqueue low watermark per-knote for mmaped channels.Thu, Jun 25, 8:57 PM

I think the proper change would be to patch chn_polltrigger to accept pointer to knote and if it's NULL, do what it does now, if it's not, do what this patch does, but that would require changing chn_pollreset and pulling in struct knote into channel.h which I'm not sure we want or not, so please advise.

I think now the patch is fully up to @christos opinion to take.

chn_polltrigger() has a case for CHN_F_MMAP, isn't it enough? And if not, why?

It's not about mmap, it's about kqueue. Look at the following code:

if (bs->prev_total < c->lw)
    delta = c->lw;
else
    delta = bs->total - bs->prev_total;

For this to report discrete events, prev_total must be reset to total after each firing. The select/poll path does exactly that inside chn_poll():

if (chn_polltrigger(c)) {
    chn_pollreset(c);
    ...
}

Kqueue cannot safely use that same per-channel reset for two reasons:

  1. Activation/delivery race. If you reset prev_total inside dsp_kqevent() when KNOTE_LOCKED activates the knote, the event has not yet been delivered to userland. The next interrupt runs kn_scan() again, sees total - prev_total < lw, and drops the event.
  2. Multiple knotes on one channel share prev_total. If two kevent registrations are watching the same channel, resetting prev_total for one knote prevents the other from ever seeing its own low-watermark edge.

So chn_polltrigger()'s mmap logic is correct, but it needs a per-caller counter. Select/poll uses the single per-channel prev_total because each poll call is a fresh, one-shot evaluation. Kqueue needs a separate counter per knote, which is kn_sdata.