[alsa-devel] Third time: Unlink PCM resource ?
Hello,
This is the third time I tried to get information on the same topic but there has been no response. Since it is crucial for me to get this to work, I really would appreciate your input. If necssary I can provide further documentation. The problem is as follows: if a process which opened a DSP device forks of a new process, then this child will have the same handle towards the DSP. What I now want to do is to release the handle in the child without closing the device for the parent as well. So essentially the sequence below illustrates the problem if one is unable to 'unlink' a dsp device.
a- parent process creates and open dsp device b- parent process forks of a child 1. Child 1 has access to the same dsp device c- parent process closes the DSP device d- client process can no longer write to the DSP device (these are already odd semantics, but okay, can live with it) e- parent process forks of a second child. Child 2 has no dsp device f- Child 2 tries to open the DSP device. This fails because the device, although closed, is not released yet by Child 1.
Is this normal behavior ? Is there some rigid documentation on the closing and sharing semantics of pcm devices ? Is there a way to unlink a device without closing it ?
If this is the wrong mailinglist, then who should I contact regarding these erratic semantics ?
Wkr,
At Mon, 25 May 2009 17:30:19 +0200, Werner Van Belle wrote:
Hello,
This is the third time I tried to get information on the same topic but there has been no response. Since it is crucial for me to get this to work, I really would appreciate your input. If necssary I can provide further documentation. The problem is as follows: if a process which opened a DSP device forks of a new process, then this child will have the same handle towards the DSP. What I now want to do is to release the handle in the child without closing the device for the parent as well. So essentially the sequence below illustrates the problem if one is unable to 'unlink' a dsp device.
a- parent process creates and open dsp device b- parent process forks of a child 1. Child 1 has access to the same dsp device c- parent process closes the DSP device d- client process can no longer write to the DSP device (these are already odd semantics, but okay, can live with it) e- parent process forks of a second child. Child 2 has no dsp device f- Child 2 tries to open the DSP device. This fails because the device, although closed, is not released yet by Child 1.
Is this normal behavior ?
Is there some rigid documentation on the closing and sharing semantics of pcm devices ? Is there a way to unlink a device without closing it ?
Unlikely.
If this is the wrong mailinglist, then who should I contact regarding these erratic semantics ?
Which API are you using? A simple test case code would be more helpful to demonstrate.
But, in general, sharing the same DSP device among different processes don't sound like a good idea...
Takashi
Takashi Iwai wrote:
If this is the wrong mailinglist, then who should I contact regarding these erratic semantics ?
Which API are you using? A simple test case code would be more helpful to demonstrate.
The api provided by libasound. I'll see whether I can generate a concise example if there is no known solution to this problem,
But, in general, sharing the same DSP device among different processes don't sound like a good idea...
I agree, but when one forks off a child the parent pcm handle automatically passes to the child. If there is a possibility _not_ to pass the PCM handle to the forked process then I would be quite happy as well.
Werner,-
On Mon, 25 May 2009, Werner Van Belle wrote:
I agree, but when one forks off a child the parent pcm handle automatically passes to the child. If there is a possibility _not_ to pass the PCM handle to the forked process then I would be quite happy as well.
Do you call close() for all opened file descriptors associated to snd_pcm_t handle in child process?
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
Jaroslav Kysela wrote:
Do you call close() for all opened file descriptors associated to snd_pcm_t handle in child process?
I use snd_pcm_close() in the child process, but this will also close the parent process its pcm device, which is clearly not wanted.
Wkr,
Werner,-
At Mon, 25 May 2009 19:52:47 +0200, Werner Van Belle wrote:
But, in general, sharing the same DSP device among different processes don't sound like a good idea...
I agree, but when one forks off a child the parent pcm handle automatically passes to the child. If there is a possibility _not_ to pass the PCM handle to the forked process then I would be quite happy as well.
You can control it via fcntl(). See fcntl(2) man page.
Takashi
Takashi Iwai wrote:
You can control it via fcntl(). See fcntl(2) man page.
I looked at that but I didn't find any place in alsalib (or libalsa whatever the order of those two words), where I can obtain the file handle. They are all of type pcm_something_t. I found a file handle quite deep in this library but there seems no way to actually obtain that handle.
Do you think fcntl on a pcm_t device would work (if we got it to compile first :-)
Werner,-
On Mon, 25 May 2009, Werner Van Belle wrote:
Takashi Iwai wrote:
You can control it via fcntl(). See fcntl(2) man page.
I looked at that but I didn't find any place in alsalib (or libalsa whatever the order of those two words), where I can obtain the file handle. They are all of type pcm_something_t. I found a file handle quite deep in this library but there seems no way to actually obtain that handle.
Do you think fcntl on a pcm_t device would work (if we got it to compile first :-)
snd_pcm_poll_descriptors / snd_pcm_poll_descriptors_count
But I wonder why snd_pcm_close() does not work in child process. Could you show us 'strace -f -e trace=open,close' for your program?
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
At Mon, 25 May 2009 20:31:42 +0200 (CEST), Jaroslav Kysela wrote:
On Mon, 25 May 2009, Werner Van Belle wrote:
Takashi Iwai wrote:
You can control it via fcntl(). See fcntl(2) man page.
I looked at that but I didn't find any place in alsalib (or libalsa whatever the order of those two words), where I can obtain the file handle. They are all of type pcm_something_t. I found a file handle quite deep in this library but there seems no way to actually obtain that handle.
Do you think fcntl on a pcm_t device would work (if we got it to compile first :-)
snd_pcm_poll_descriptors / snd_pcm_poll_descriptors_count
... which doesn't return always all used fd's.
But I wonder why snd_pcm_close() does not work in child process. Could you show us 'strace -f -e trace=open,close' for your program?
Passing O_CLOEXEC would be the best solution, I think. We just need a few additions.
Takashi
At Mon, 25 May 2009 20:27:14 +0200, Werner Van Belle wrote:
Takashi Iwai wrote:
You can control it via fcntl(). See fcntl(2) man page.
I looked at that but I didn't find any place in alsalib (or libalsa whatever the order of those two words), where I can obtain the file handle. They are all of type pcm_something_t. I found a file handle quite deep in this library but there seems no way to actually obtain that handle.
OK, I see the problem now, too. In practice, you can get a file descriptor from poll descriptor, but this doesn't cover all underlying fds. A new API function or an additional SND_PCM_* flag for snd_pcm_open() would be needed, indeed.
In the latter case, it must be easy -- just pass O_CLOEXEC flag to open() call...
Takashi
On Mon, 25 May 2009, Takashi Iwai wrote:
At Mon, 25 May 2009 20:27:14 +0200, Werner Van Belle wrote:
Takashi Iwai wrote:
You can control it via fcntl(). See fcntl(2) man page.
I looked at that but I didn't find any place in alsalib (or libalsa whatever the order of those two words), where I can obtain the file handle. They are all of type pcm_something_t. I found a file handle quite deep in this library but there seems no way to actually obtain that handle.
OK, I see the problem now, too. In practice, you can get a file descriptor from poll descriptor, but this doesn't cover all underlying fds. A new API function or an additional SND_PCM_* flag for snd_pcm_open() would be needed, indeed.
The question is if it's not better to free also allocated memory associated to the pcm handle in child process - so snd_pcm_close() call in child is not a bad idea.
Jaroslav ----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
Jaroslav Kysela wrote:
The question is if it's not better to free also allocated memory associated to the pcm handle in child process - so snd_pcm_close() call in child is not a bad idea.
Okay, while you both have been discussing some internals, which I didn't try yet, I created a demonstration program to illustrate the mixed semantics of the 'sharing' versus 'not sharing' behavior of the dsp devices. In the example the parent thread will play a sound, then the child closes the dsp, which affects the playback in the parent (it either hangs or skips all remaining samples). From this one would conclude that the pcm device is fully shared between the two processes (semantics I can live with). However, when the parent then tries to reopen the device it cannot do so because the device is still 'busy'.
As a solution, a call to an unlink function would maybe solve it but it is indicative of a deeper unclarity of how the semantics of shared DSP devices should be. I would propose to let alsa act as a true filehandle. In such a scenario a close in the child should not affect the playback in the parent since the parent still has the descriptor open. Please have a look at the attached code. It is 256 lines :-) The problem is documented in the main routine.
With kind regards,
Werner,-
On Mon, 25 May 2009, Werner Van Belle wrote:
Jaroslav Kysela wrote:
The question is if it's not better to free also allocated memory associated to the pcm handle in child process - so snd_pcm_close() call in child is not a bad idea.
Okay, while you both have been discussing some internals, which I didn't try yet, I created a demonstration program to illustrate the mixed semantics of the 'sharing' versus 'not sharing' behavior of the dsp devices. In the example the parent thread will play a sound, then the child closes the dsp, which affects the playback in the parent (it either hangs or skips all remaining samples). From this one would conclude that the pcm device is fully shared between the two processes (semantics I can live with). However, when the parent then tries to reopen the device it cannot do so because the device is still 'busy'.
Your example program does not contain dsp_close() call in parent before dsp_open(). That's reason why PCM device is blocked.
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
Jaroslav Kysela wrote:
Your example program does not contain dsp_close() call in parent before dsp_open(). That's reason why PCM device is blocked.
That could make sense, but then the wave should not stop playing when the child process closes the dsp ? Currently the child process has no way to release the dsp without stopping the parent process during play.
Werner,-
At Mon, 25 May 2009 20:39:45 +0200 (CEST), Jaroslav Kysela wrote:
On Mon, 25 May 2009, Takashi Iwai wrote:
At Mon, 25 May 2009 20:27:14 +0200, Werner Van Belle wrote:
Takashi Iwai wrote:
You can control it via fcntl(). See fcntl(2) man page.
I looked at that but I didn't find any place in alsalib (or libalsa whatever the order of those two words), where I can obtain the file handle. They are all of type pcm_something_t. I found a file handle quite deep in this library but there seems no way to actually obtain that handle.
OK, I see the problem now, too. In practice, you can get a file descriptor from poll descriptor, but this doesn't cover all underlying fds. A new API function or an additional SND_PCM_* flag for snd_pcm_open() would be needed, indeed.
The question is if it's not better to free also allocated memory associated to the pcm handle in child process - so snd_pcm_close() call in child is not a bad idea.
OK, in a case without exec, we need an explicit call. But I guess snd_pcm_close() isn't appropriate (as Werner experienced) since it calls snd_pcm_drop() there. I guess this call isn't needed as the driver itself takes care?
Takashi
Takashi Iwai wrote:
OK, in a case without exec, we need an explicit call. But I guess snd_pcm_close() isn't appropriate (as Werner experienced) since it calls snd_pcm_drop() there. I guess this call isn't needed as the driver itself takes care?
You mean: modifying the snd_pcm_close routine to not call snd_pcm_drop ? I guess that might work as well to solve my problem. Will such a fix appear in a new alsa release ?
I'd like to thank you for the time you spent to look at this issue.
With kind regards,
Werner,-
At Tue, 26 May 2009 10:14:56 +0200, Werner Van Belle wrote:
Takashi Iwai wrote:
OK, in a case without exec, we need an explicit call. But I guess snd_pcm_close() isn't appropriate (as Werner experienced) since it calls snd_pcm_drop() there. I guess this call isn't needed as the driver itself takes care?
You mean: modifying the snd_pcm_close routine to not call snd_pcm_drop ?
Yes.
I guess that might work as well to solve my problem. Will such a fix appear in a new alsa release ?
We need more tests :) I might overlook something.
Takashi
At Tue, 26 May 2009 10:17:41 +0200, I wrote:
At Tue, 26 May 2009 10:14:56 +0200, Werner Van Belle wrote:
Takashi Iwai wrote:
OK, in a case without exec, we need an explicit call. But I guess snd_pcm_close() isn't appropriate (as Werner experienced) since it calls snd_pcm_drop() there. I guess this call isn't needed as the driver itself takes care?
You mean: modifying the snd_pcm_close routine to not call snd_pcm_drop ?
Yes.
I guess that might work as well to solve my problem. Will such a fix appear in a new alsa release ?
We need more tests :) I might overlook something.
Finally had some time to take a look at this pending issue...
Through tests, I found that this can be really a problem, too. The below is a quick fix, adding a new function, snd_pcm_detach(). This works like snd_pcm_close() but without stopping it. Give it a try.
If anyone sees a problem with it, let me know.
thanks,
Takashi
--- From bdbce35b6d582d4ee4a0813190f09232bd8dc02c Mon Sep 17 00:00:00 2001 From: Takashi Iwai tiwai@suse.de Date: Tue, 7 Jul 2009 16:59:09 +0200 Subject: [PATCH] Add snd_pcm_detach() function
Added a new function, snd_pcm_detach(). This function closes the given PCM stream without stopping. It's useful for closing the inherited PCM stream after forking without interfering the parent process.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/pcm.h | 1 + src/pcm/pcm.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/include/pcm.h b/include/pcm.h index 15e9cb2..9992d53 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -412,6 +412,7 @@ int snd_pcm_open_lconf(snd_pcm_t **pcm, const char *name, snd_config_t *lconf);
int snd_pcm_close(snd_pcm_t *pcm); +int snd_pcm_detach(snd_pcm_t *pcm); const char *snd_pcm_name(snd_pcm_t *pcm); snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm); snd_pcm_stream_t snd_pcm_stream(snd_pcm_t *pcm); diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index e63bbe9..059840f 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -713,6 +713,22 @@ int snd_pcm_close(snd_pcm_t *pcm) }
/** + * \brief close PCM handle without stopping the assigned stream + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * Closes the specified PCM handle without stopping the stream. + * This can be useful if you need to close and release the inherited + * PCM stream after forking. Unlike snd_pcm_stop(), this function + * doesn't influence the PCM stream of the parent. + */ +int snd_pcm_detach(snd_pcm_t *pcm) +{ + pcm->donot_close = 1; + return snd_pcm_close(pcm); +} + +/** * \brief set nonblock mode * \param pcm PCM handle * \param nonblock 0 = block, 1 = nonblock mode
Takashi Iwai wrote:
OK, I see the problem now, too. In practice, you can get a file descriptor from poll descriptor, but this doesn't cover all underlying fds. A new API function or an additional SND_PCM_* flag for snd_pcm_open() would be needed, indeed.
In the latter case, it must be easy -- just pass O_CLOEXEC flag to open() call...
That handles the close on exec well, but we are talking about forks here. There is not necessarily an exec involved in the child process.
Wkr,
Werner,-
participants (3)
-
Jaroslav Kysela
-
Takashi Iwai
-
Werner Van Belle