Page MenuHomeFreeBSD

sound: Add kqueue support
ClosedPublic

Authored by christos on Oct 10 2025, 4:47 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Nov 22, 6:29 AM
Unknown Object (File)
Sat, Nov 15, 10:12 PM
Unknown Object (File)
Fri, Nov 14, 1:15 AM
Unknown Object (File)
Thu, Nov 13, 2:08 AM
Unknown Object (File)
Wed, Nov 12, 10:05 PM
Unknown Object (File)
Wed, Nov 12, 8:29 PM
Unknown Object (File)
Wed, Nov 12, 5:35 PM
Unknown Object (File)
Wed, Nov 12, 5:32 PM
Subscribers

Details

Summary

Co-authored by: meka@tilda.center
Sponsored by: The FreeBSD Foundation
MFC after: 2 weeks

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
sys/dev/sound/pcm/dsp.c
2998

This function is set only in the EVFILT_READ case in dsp_kqueue(), so I suppose it is redundant to check for kn->kn_filter == EVFILT_READ here? Same for dsp_write_filter().

Or can kn->kn_filter have a different value?

2999

From the man page description of the f_event method, I am not really sure what we want to store here. Is there a particular reason you chose sndbuf_getallocsize()?

I changed the code based on the comments, but I didn't add test program, yet. Give me some more time.

meka_tilda.center added inline comments.
sys/dev/sound/pcm/dsp.c
2999

I saw what SNDCTL_DSP_GETOSPACE does and did the same.

meka_tilda.center marked an inline comment as done.

While at it, I decided to add all polling/events into one example.

I was wrong about what SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE do, hence the update.

arrowd added inline comments.
share/examples/sound/oss/audio.c
363

The EXAMPLE_POLL case waits on POLLIN, but here we arm the EVFILT_WRITE event. It feels like it should be EVFILT_READ instead?

The test patch should be a separate commit. You can link to it here in the "Test Plan" section (click "Edit Revision" and you'll see it). But I'm starting to think this is becoming more of a test program than an example one. Maybe we should think about it moving it to tests, and making some more straight-forward ones for /usr/share/examples.

share/examples/sound/oss/audio.c
41

Better to have this above sys/soundcard.h, as per style(9).

sys/dev/sound/pcm/dsp.c
2989

Why do we call knlist_remove() only when CHN_F_DEAD is not set, but dsp_kqfilter() calls knlist_add() unconditionally? This is not a hint to remove the check, but to understand why the check is here in the first place.

3009

According to kqueue.9:

The kn_data value should be updated as necessary to reflect the current value, such as number of bytes available for reading, or buffer space available for writing.

Here we assign kn_data to an errno value instead. Shouldn't we assign it to 0?

3011

Doesn't a return value of 1 indicate that there was no error?

3067

You can assign this to 0 here and avoid setting it to 0 below for every case.

There are a lot of unresolved reviewer's notes. Do you really need more reviewers, at least until all existing suggestions are handled?

sys/dev/sound/pcm/dsp.c
3033

I do not think that cdevpriv pointer is ever set for the context of the kqueue read or write filters. You should have enough context in the knote itself to fetch everything needed to check for the filter conditions.

3044

Extra empty line

3105
In D53029#1214200, @kib wrote:

Do you really need more reviewers, at least until all existing suggestions are handled?

I added you as a reviewer, not Meka, in case you want to take a look at it as well.

sys/dev/sound/pcm/dsp.c
3033

If that's the case, kn_hook in dsp_kqfilter() can just be the cdevpriv and we can then fetch the appropriate channel here through it. We do the same in dsp_read() and dsp_write().

Most notable change is removal of example, I'll add it in a new revision.

meka_tilda.center added inline comments.
sys/dev/sound/pcm/dsp.c
2989

I thought that if channel was dead, it already detached the queue. I would need to think about how to test this.

3009

If you look at kqueue(2) example, there is

if (tevent.flags & EV_ERROR)
    errx(EXIT_FAILURE, "Event error: %s", strerror(event.data));

So I think this works according to kqueue specs.

3011

No, it indicates if knote is still valid or not. That's how cuse does it, hence virtual_oss behaves the same.

sys/dev/sound/pcm/dsp.c
3009

@kib Is there some kind of mismatch between kqueue.9 and kqueue.2, or do I just misunderstand something? Because kqueue.9 does not specify that, as I mentioned above.

3011

I am not 100% sure I understand what kqueue.2's RETURN VALUES section tries to say to be honest, as in, I do not really get when we should return -1 and when !0.

sys/dev/sound/pcm/dsp.c
3041
3089
meka_tilda.center marked 2 inline comments as done.

Fixed typos

sys/dev/sound/pcm/dsp.c
3009

I had much problems figuring out how to add kqueue support and as virtual_oss uses cuse, I used cuse's implementation of kqueue support as reference. In the process I did add my notes to kqueue(9) in a separate branch in my github fork. One of my goals of this implementation is to make that man page better, but one thing at a time.

sys/dev/sound/pcm/dsp.c
3011

Can you say exactly which sentences from kqueue.2 and kqueue.9 contradicts each other?

That said, neither of man pages ever states that knote f_event returns an error. f_event should return 0 for inactive knote, and non-zero if knot was activated somehow.

sys/dev/sound/pcm/dsp.c
3011

My comment about mismatching (not contradicting) statements between kqueue.2 and kqueue.9 is above, it does not refer to here. kqueue.9 says that kn_data holds the value of available bytes for reading/buffer spacing available for writing, but kqueue.2 shows event.data holding an errno value in case of an error, but this is not documented in kqueue.9.

sys/dev/sound/pcm/dsp.c
3011

Practically filters never return errors. And definitely they do not set EV_ERROR, I would be curious to see an example. EV_ERROR is described conscientiously in kqueue.2.

The reason why filters do not need to return error is because registered knotes must be torn down before the object they monitor is destroyed. If the object is lingering in error state, there is simply nothing to report, so knotes should be not activated.

When a knote is activated, then kn_data become something that knote set according to the semantic of its filter.

I've been testing the patch and trying to fix the panic you mentioned in D53029, although there is one more panic in dsp_kqdetach() that I'm working on. The code needs a few changes, is it okay if I take over the revision, at least for now, so that it's easier to upload the new changes?

I've been testing the patch and trying to fix the panic you mentioned in D53029, although there is one more panic in dsp_kqdetach() that I'm working on. The code needs a few changes, is it okay if I take over the revision, at least for now, so that it's easier to upload the new changes?

To be honest, I hoped you'll say that if I expose the bug in a somewhat repeatable way 😄 Anyway, go for it and good luck!

christos retitled this revision from Add kqueue(9) support to sound(4) to sound: Add kqueue(9) support.
christos edited the summary of this revision. (Show Details)
christos edited reviewers, added: meka_tilda.center; removed: christos.

Take over revision, at least for now. All tests in D53188 pass with the new
changes.

  • Fix panic in the filter functions, and do not acquire locks inside them, per kqueue.9.
  • Fix a crash in dsp_kqdetach(), which was a result of unconditionally calling knlist_remove() on both channels, which means that if, for example, we set only EVFILT_WRITE (like in the test in D53188), we will call knlist_remove() on both the read and the write channels, but the read one will cause a panic inside knlist_remove_kq(), because we haven't called knlist_add() for it in dsp_kqfilter().
  • Fix a hang resulting from KNOTE_LOCKED() not being called in chn_wakeup().
  • Do not enter Giant in dsp_kqdetach(), but I am actually not 100% sure if we need it or not.
christos retitled this revision from sound: Add kqueue(9) support to sound: Add kqueue support.Oct 21 2025, 12:36 PM
christos edited the summary of this revision. (Show Details)
christos edited the summary of this revision. (Show Details)

Clean up more.

  • s/LOCKOWNED/LOCKASSERT/
  • Use chn_polltrigger() to determine whether we are ready for IO. This how chn_poll() already works for servicing poll(2) and select(2).
  • Initialize and destroy the knlist in chn_init() and chn_kill() respectively, as opposed to dsp_open() and dsp_close().

Questions to @kib and @markj:

  • Are the return values from dsp_kqevent() correct?
sys/dev/sound/pcm/dsp.c
3009

Is it actually possible to have !DSP_REGISTERED() here? Shouldn't we have drained knotes by that point?

3023

This function should be structured so that this default case can't happen. dsp_kqfilter() can set kn->kn_ptr.p_v = ch and then this function can obtain the channel directly.

3027

kn_data shouldn't be abused to return an error number. You can use kn_fflags to return this instead, if it's necessary. More standard would be to set EV_EOF and return 1, I suspect.

christos added inline comments.
sys/dev/sound/pcm/dsp.c
3009

Good point.

3023

Looking again into this, I suppose this case already cannot happen since dsp_kqfilter() won't add a knlist for the default case, right?

3027

I was actually saying the same thing in previous comments (see right above).

sys/dev/sound/pcm/dsp.c
3023

Also since we can remove the DSP_REGISTERED() check, we can instead pass the channel to kn->kn_hook now.

sys/dev/sound/pcm/dsp.c
3027

Do we have good docs on what to return when hardware dies? I've seen a mix of ENXIO and ENODEV and kinda think the former is better since the latter indicates it's not supported (or so the error message says, with these in-kernel protocols, it's hard to say for sure). But I also know that's a storage-centric view since that's what we do there when the device is gone and is in a state where it can't come back.

Simplify dsp_kqdetach() also.

Bump. Would like to commit it if possible.

Looks ok to me aside from the comment.

sys/dev/sound/pcm/dsp.c
2991

I don't see how it's possible to have ch == NULL here. If there is no channel we won't create the knote to begin with.

This revision is now accepted and ready to land.Tue, Nov 11, 12:15 AM
This revision was automatically updated to reflect the committed changes.