Thu Aug 29 13:01:07 2019 UTC ()
Fix lock assertion on async I/O mode.
psignal() must be called without any spin locks.
Thanks maxv@!


(isaki)
diff -r1.29 -r1.30 src/sys/dev/audio/audio.c
diff -r1.4 -r1.5 src/sys/dev/audio/audiovar.h

cvs diff -r1.29 -r1.30 src/sys/dev/audio/audio.c (expand / switch to unified diff)

--- src/sys/dev/audio/audio.c 2019/08/23 09:41:26 1.29
+++ src/sys/dev/audio/audio.c 2019/08/29 13:01:07 1.30
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: audio.c,v 1.29 2019/08/23 09:41:26 maxv Exp $ */ 1/* $NetBSD: audio.c,v 1.30 2019/08/29 13:01:07 isaki Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran. 8 * by Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -132,27 +132,27 @@ @@ -132,27 +132,27 @@
132 * these may be also called after attach, the thread lock is required. 132 * these may be also called after attach, the thread lock is required.
133 * 133 *
134 * In addition, there is an additional lock. 134 * In addition, there is an additional lock.
135 * 135 *
136 * - track->lock. This is an atomic variable and is similar to the 136 * - track->lock. This is an atomic variable and is similar to the
137 * "interrupt lock". This is one for each track. If any thread context 137 * "interrupt lock". This is one for each track. If any thread context
138 * (and software interrupt context) and hardware interrupt context who 138 * (and software interrupt context) and hardware interrupt context who
139 * want to access some variables on this track, they must acquire this 139 * want to access some variables on this track, they must acquire this
140 * lock before. It protects track's consistency between hardware 140 * lock before. It protects track's consistency between hardware
141 * interrupt context and others. 141 * interrupt context and others.
142 */ 142 */
143 143
144#include <sys/cdefs.h> 144#include <sys/cdefs.h>
145__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.29 2019/08/23 09:41:26 maxv Exp $"); 145__KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.30 2019/08/29 13:01:07 isaki Exp $");
146 146
147#ifdef _KERNEL_OPT 147#ifdef _KERNEL_OPT
148#include "audio.h" 148#include "audio.h"
149#include "midi.h" 149#include "midi.h"
150#endif 150#endif
151 151
152#if NAUDIO > 0 152#if NAUDIO > 0
153 153
154#ifdef _KERNEL 154#ifdef _KERNEL
155 155
156#include <sys/types.h> 156#include <sys/types.h>
157#include <sys/param.h> 157#include <sys/param.h>
158#include <sys/atomic.h> 158#include <sys/atomic.h>
@@ -5720,67 +5720,93 @@ audio_track_drain(struct audio_softc *sc @@ -5720,67 +5720,93 @@ audio_track_drain(struct audio_softc *sc
5720 if (error) 5720 if (error)
5721 return error; 5721 return error;
5722 5722
5723 /* XXX call audio_track_play here ? */ 5723 /* XXX call audio_track_play here ? */
5724 } 5724 }
5725 5725
5726 track->pstate = AUDIO_STATE_CLEAR; 5726 track->pstate = AUDIO_STATE_CLEAR;
5727 TRACET(3, track, "done trk_inp=%d trk_out=%d", 5727 TRACET(3, track, "done trk_inp=%d trk_out=%d",
5728 (int)track->inputcounter, (int)track->outputcounter); 5728 (int)track->inputcounter, (int)track->outputcounter);
5729 return 0; 5729 return 0;
5730} 5730}
5731 5731
5732/* 5732/*
 5733 * Send signal to process.
 5734 * This is intended to be called only from audio_softintr_{rd,wr}.
 5735 * Must be called with sc_lock && sc_intr_lock held.
 5736 */
 5737static inline void
 5738audio_psignal(struct audio_softc *sc, pid_t pid, int signum)
 5739{
 5740 proc_t *p;
 5741
 5742 KASSERT(mutex_owned(sc->sc_lock));
 5743 KASSERT(mutex_owned(sc->sc_intr_lock));
 5744 KASSERT(pid != 0);
 5745
 5746 /*
 5747 * psignal() must be called without spin lock held.
 5748 * So leave intr_lock temporarily here.
 5749 */
 5750 mutex_exit(sc->sc_intr_lock);
 5751
 5752 mutex_enter(proc_lock);
 5753 p = proc_find(pid);
 5754 if (p)
 5755 psignal(p, signum);
 5756 mutex_exit(proc_lock);
 5757
 5758 /* Enter intr_lock again */
 5759 mutex_enter(sc->sc_intr_lock);
 5760}
 5761
 5762/*
5733 * This is software interrupt handler for record. 5763 * This is software interrupt handler for record.
5734 * It is called from recording hardware interrupt everytime. 5764 * It is called from recording hardware interrupt everytime.
5735 * It does: 5765 * It does:
5736 * - Deliver SIGIO for all async processes. 5766 * - Deliver SIGIO for all async processes.
5737 * - Notify to audio_read() that data has arrived. 5767 * - Notify to audio_read() that data has arrived.
5738 * - selnotify() for select/poll-ing processes. 5768 * - selnotify() for select/poll-ing processes.
5739 */ 5769 */
5740/* 5770/*
5741 * XXX If a process issues FIOASYNC between hardware interrupt and 5771 * XXX If a process issues FIOASYNC between hardware interrupt and
5742 * software interrupt, (stray) SIGIO will be sent to the process 5772 * software interrupt, (stray) SIGIO will be sent to the process
5743 * despite the fact that it has not receive recorded data yet. 5773 * despite the fact that it has not receive recorded data yet.
5744 */ 5774 */
5745static void 5775static void
5746audio_softintr_rd(void *cookie) 5776audio_softintr_rd(void *cookie)
5747{ 5777{
5748 struct audio_softc *sc = cookie; 5778 struct audio_softc *sc = cookie;
5749 audio_file_t *f; 5779 audio_file_t *f;
5750 proc_t *p; 
5751 pid_t pid; 5780 pid_t pid;
5752 5781
5753 mutex_enter(sc->sc_lock); 5782 mutex_enter(sc->sc_lock);
5754 mutex_enter(sc->sc_intr_lock); 5783 mutex_enter(sc->sc_intr_lock);
5755 5784
5756 SLIST_FOREACH(f, &sc->sc_files, entry) { 5785 SLIST_FOREACH(f, &sc->sc_files, entry) {
5757 audio_track_t *track = f->rtrack; 5786 audio_track_t *track = f->rtrack;
5758 5787
5759 if (track == NULL) 5788 if (track == NULL)
5760 continue; 5789 continue;
5761 5790
5762 TRACET(4, track, "broadcast; inp=%d/%d/%d", 5791 TRACET(4, track, "broadcast; inp=%d/%d/%d",
5763 track->input->head, 5792 track->input->head,
5764 track->input->used, 5793 track->input->used,
5765 track->input->capacity); 5794 track->input->capacity);
5766 5795
5767 pid = f->async_audio; 5796 pid = f->async_audio;
5768 if (pid != 0) { 5797 if (pid != 0) {
5769 TRACEF(4, f, "sending SIGIO %d", pid); 5798 TRACEF(4, f, "sending SIGIO %d", pid);
5770 mutex_enter(proc_lock); 5799 audio_psignal(sc, pid, SIGIO);
5771 if ((p = proc_find(pid)) != NULL) 
5772 psignal(p, SIGIO); 
5773 mutex_exit(proc_lock); 
5774 } 5800 }
5775 } 5801 }
5776 mutex_exit(sc->sc_intr_lock); 5802 mutex_exit(sc->sc_intr_lock);
5777 5803
5778 /* Notify that data has arrived. */ 5804 /* Notify that data has arrived. */
5779 selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT); 5805 selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT);
5780 KNOTE(&sc->sc_rsel.sel_klist, 0); 5806 KNOTE(&sc->sc_rsel.sel_klist, 0);
5781 cv_broadcast(&sc->sc_rmixer->outcv); 5807 cv_broadcast(&sc->sc_rmixer->outcv);
5782 5808
5783 mutex_exit(sc->sc_lock); 5809 mutex_exit(sc->sc_lock);
5784} 5810}
5785 5811
5786/* 5812/*
@@ -5789,61 +5815,59 @@ audio_softintr_rd(void *cookie) @@ -5789,61 +5815,59 @@ audio_softintr_rd(void *cookie)
5789 * It does: 5815 * It does:
5790 * - Deliver SIGIO for all async and writable (used < lowat) processes. 5816 * - Deliver SIGIO for all async and writable (used < lowat) processes.
5791 * - Notify to audio_write() that outbuf block available. 5817 * - Notify to audio_write() that outbuf block available.
5792 * - selnotify() for select/poll-ing processes if there are any writable 5818 * - selnotify() for select/poll-ing processes if there are any writable
5793 * (used < lowat) processes. Checking each descriptor will be done by 5819 * (used < lowat) processes. Checking each descriptor will be done by
5794 * filt_audiowrite_event(). 5820 * filt_audiowrite_event().
5795 */ 5821 */
5796static void 5822static void
5797audio_softintr_wr(void *cookie) 5823audio_softintr_wr(void *cookie)
5798{ 5824{
5799 struct audio_softc *sc = cookie; 5825 struct audio_softc *sc = cookie;
5800 audio_file_t *f; 5826 audio_file_t *f;
5801 bool found; 5827 bool found;
5802 proc_t *p; 
5803 pid_t pid; 5828 pid_t pid;
5804 5829
5805 TRACE(4, "called"); 5830 TRACE(4, "called");
5806 found = false; 5831 found = false;
5807 5832
5808 mutex_enter(sc->sc_lock); 5833 mutex_enter(sc->sc_lock);
5809 mutex_enter(sc->sc_intr_lock); 5834 mutex_enter(sc->sc_intr_lock);
5810 5835
5811 SLIST_FOREACH(f, &sc->sc_files, entry) { 5836 SLIST_FOREACH(f, &sc->sc_files, entry) {
5812 audio_track_t *track = f->ptrack; 5837 audio_track_t *track = f->ptrack;
5813 5838
5814 if (track == NULL) 5839 if (track == NULL)
5815 continue; 5840 continue;
5816 5841
5817 TRACET(4, track, "broadcast; trseq=%d out=%d/%d/%d", 5842 TRACET(4, track, "broadcast; trseq=%d out=%d/%d/%d",
5818 (int)track->seq, 5843 (int)track->seq,
5819 track->outbuf.head, 5844 track->outbuf.head,
5820 track->outbuf.used, 5845 track->outbuf.used,
5821 track->outbuf.capacity); 5846 track->outbuf.capacity);
5822 5847
5823 /* 5848 /*
5824 * Send a signal if the process is async mode and 5849 * Send a signal if the process is async mode and
5825 * used is lower than lowat. 5850 * used is lower than lowat.
5826 */ 5851 */
5827 if (track->usrbuf.used <= track->usrbuf_usedlow && 5852 if (track->usrbuf.used <= track->usrbuf_usedlow &&
5828 !track->is_pause) { 5853 !track->is_pause) {
 5854 /* For selnotify */
5829 found = true; 5855 found = true;
 5856 /* For SIGIO */
5830 pid = f->async_audio; 5857 pid = f->async_audio;
5831 if (pid != 0) { 5858 if (pid != 0) {
5832 TRACEF(4, f, "sending SIGIO %d", pid); 5859 TRACEF(4, f, "sending SIGIO %d", pid);
5833 mutex_enter(proc_lock); 5860 audio_psignal(sc, pid, SIGIO);
5834 if ((p = proc_find(pid)) != NULL) 
5835 psignal(p, SIGIO); 
5836 mutex_exit(proc_lock); 
5837 } 5861 }
5838 } 5862 }
5839 } 5863 }
5840 mutex_exit(sc->sc_intr_lock); 5864 mutex_exit(sc->sc_intr_lock);
5841 5865
5842 /* 5866 /*
5843 * Notify for select/poll when someone become writable. 5867 * Notify for select/poll when someone become writable.
5844 * It needs sc_lock (and not sc_intr_lock). 5868 * It needs sc_lock (and not sc_intr_lock).
5845 */ 5869 */
5846 if (found) { 5870 if (found) {
5847 TRACE(4, "selnotify"); 5871 TRACE(4, "selnotify");
5848 selnotify(&sc->sc_wsel, 0, NOTE_SUBMIT); 5872 selnotify(&sc->sc_wsel, 0, NOTE_SUBMIT);
5849 KNOTE(&sc->sc_wsel.sel_klist, 0); 5873 KNOTE(&sc->sc_wsel.sel_klist, 0);

cvs diff -r1.4 -r1.5 src/sys/dev/audio/audiovar.h (expand / switch to unified diff)

--- src/sys/dev/audio/audiovar.h 2019/06/26 06:57:45 1.4
+++ src/sys/dev/audio/audiovar.h 2019/08/29 13:01:07 1.5
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: audiovar.h,v 1.4 2019/06/26 06:57:45 isaki Exp $ */ 1/* $NetBSD: audiovar.h,v 1.5 2019/08/29 13:01:07 isaki Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by TAMURA Kent 8 * by TAMURA Kent
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -139,27 +139,28 @@ struct audio_softc { @@ -139,27 +139,28 @@ struct audio_softc {
139 * hw_if == NULL means that the device is (attached but) disabled. 139 * hw_if == NULL means that the device is (attached but) disabled.
140 */ 140 */
141 const struct audio_hw_if *hw_if; 141 const struct audio_hw_if *hw_if;
142 void *hw_hdl; 142 void *hw_hdl;
143 143
144 /* 144 /*
145 * Properties obtained by get_props(). 145 * Properties obtained by get_props().
146 * No need any locks to read this variable. 146 * No need any locks to read this variable.
147 */ 147 */
148 int sc_props; 148 int sc_props;
149 149
150 /* 150 /*
151 * List of opened descriptors. 151 * List of opened descriptors.
152 * Must be protected by sc_intr_lock. 152 * Must be protected by sc_lock || sc_intr_lock for traversal(FOREACH).
 153 * Must be protected by sc_lock && sc_intr_lock for insertion/removal.
153 */ 154 */
154 SLIST_HEAD(, audio_file) sc_files; 155 SLIST_HEAD(, audio_file) sc_files;
155 156
156 /* 157 /*
157 * Blocksize in msec. 158 * Blocksize in msec.
158 * Must be protected by sc_lock. 159 * Must be protected by sc_lock.
159 */ 160 */
160 int sc_blk_ms; 161 int sc_blk_ms;
161 162
162 /* 163 /*
163 * Track mixer for playback and recording. 164 * Track mixer for playback and recording.
164 * If null, the mixer is disabled. 165 * If null, the mixer is disabled.
165 */ 166 */