[pulseaudio-discuss] [PATCH v8] pipe-source: implement autosuspend option

Georg Chini georg at chini.tk
Tue Feb 20 20:04:13 UTC 2018


On 20.02.2018 19:49, Raman Shishniou wrote:
> On 02/20/2018 07:02 PM, Georg Chini wrote:
>> On 20.02.2018 16:38, Raman Shyshniou wrote:
>>> Currently the pipe-source will remain running even if no
>>> writer is connected and therefore no data is produced.
>>> This patch adds the autosuspend=<bool> option to prevent this.
>>> Source will stay suspended if no writer is connected.
>>> This option is enabled by default.
>>> ---
>>>    src/modules/module-pipe-source.c | 279 +++++++++++++++++++++++++++++----------
>>>    1 file changed, 212 insertions(+), 67 deletions(-)
>>>
> I think I need post a simple pseudo code of new thread loop because it
> was completely rewritten. There are too many changes in one patch.
> It can be difficult to see the whole picture of new main loop.

Well, I applied the patch and looked at the result. I still don't like 
the approach.

I would propose this:

auto_suspended = false;
revents = 0
events = POLLIN

for (;;) {

       /* This is the part that is run when the source is opened
        * or auto suspended
       if (SOURCE_IS_OPENED(source) || auto_suspended) {

           /* Check if we wake up from user suspend */
           if (corkfd >= 0 && !auto_suspended) {
                len = 0
                close pipe for writing
           }

           /* We received POLLIN or POLLHUP or both */
           if (revents) {

              /* Read data from pipe */
              len = read data

              /* Got data, post it */
              if (len > 0) {
                  if (auto_suspend) {
                      send unsuspend message
                      auto_suspend = false
                 }
                 post data

              /* Got POLLHUP or POLLIN without data, writer disconnected */
              } else if (len = 0) {
                   send suspend message
                   auto_suspend = true
              }

              /* else Handle error */
              else
                  handle error

              events = POLLIN
          }

       /* This is the part that is run, when the source is
       * suspended by user */
       } else {

            if (corkfd < 0)
               open pipe for writing
            events = 0
      }

       /* This is run always */
       run rtpoll
       ... check errors ...
}

I think this is more consistent with how the other thread functions are
written and also has a clearer structure.

>
> pollfd = NULL;
> rtpoll_item = NULL;
> chunk.length = 0; // length of pending data in chunk.memblock
> chunk.memblock = pa_memblock_new(); // always allocated
>
> for (;;) {
>
>      /**************************************************
>       * run rtpoll
>       */
>      if (chunk.length > 0) {
>          /* we have a pending data */
>          if (rtpoll_item) {
>              /* stop polling pipe
>               * the only way to be here:
>               * source was just suspended */
>              ... free rtpoll_item ...
>              rtpoll_item = NULL;
>          }
>      } else {
>          /* we have no pending data */
>          if (rtpoll_item == NULL) {
>              /* start polling pipe
>               * the only way to be here:
>               * source was just resumed */
>              ... allocate rtpoll_item, get pollfd ...
>              pollfd->events = POLLIN;
>              pollfd->fd = u->fd;
>          }
>      }
>
>      pa_rtpoll_run()
>
>      ... check errors ...
>
>      if (rtpoll_item) {
>          /* we polled pipe */
>          ... refresh pollfd ...
>      } else
>          /* we are waiting for source state changes */
>          pollfd = NULL;
>
>      /**************************************************
>       * Read data
>       */
>      if (pollfd && pollfd->revents) {
>
>          ... read data from pipe ...
>
>          if (len > 0) {
>              chunk.length = len;
>
>              /* source is autosuspended? */
>              if (u->corkfd >= 0) {
>                  ... send resume message ...
>                  close(u->corkfd);
>                  u->corkfd = -1;
>              }
>          }
>
>          if (len == 0) {
>              /* sourece not autosuspended? */
>              if (u->corkfd < 0) {
>                  ... send suspend message ...
>                  u->corkfd = open(pipe, O_WRONLY);
>              }
>          }
>
>          if (len < 0) {
>              ... check read error ...
>          }
>      }
>
>      /**************************************************
>       * Post data
>       */
>      if (source is opened) {

After an auto-unsuspend, the result of the above comparison is undefined.
It may be that the main thread already processed the unsuspend message,
maybe not.

>          ... post data ...
>          unref(chunk.memblock);
>          chunk.memblock = pa_memblock_new();
>          chunk.length = 0;
>      }
>
>      /* chunk.length can be greater than 0 only if we are suspended right now
>       * we need to stop polling pipe and wait while state will be changed to RUNNING or IDLE
>       * to post pending data */

If we are user suspended right now, the data should never be posted. 
Data that is read
while we are user-suspended should be discarded. Data that arrives while 
we are
auto-suspended should be posted.


> }
>
> I can convert all changes to patch series if you want.
>
> --
> Raman




More information about the pulseaudio-discuss mailing list