[PATCH] serial-port: turn open_count assertion in mm_serial_port_close into simple return

Ben Chan benchan at chromium.org
Sat Jan 11 18:37:50 PST 2014


I had a typo:

2. Before *mm_serial_port_close* even finishes and returns, it invokes
a response callback of a command in priv->queue

On Sat, Jan 11, 2014 at 6:36 PM, Ben Chan <benchan at chromium.org> wrote:
> On Sat, Jan 11, 2014 at 2:32 PM, Aleksander Morgado
> <aleksander at aleksander.es> wrote:
>>
>> On 11/01/14 01:54, Ben Chan wrote:
>> > When mm_serial_port_close is clearing a non-empty command queue, the
>> > response handler callback of a command could potentially call
>> > mm_serial_port_close again (e.g. via at_command_context_free,
>> > at_sequence_context_free in mm-base-modem-at.c), which triggers the
>> > following assertion:
>> >
>> >   ModemManager: <debug> (ttyACM0) forced to close port
>> >   ModemManager: <debug> (ttyACM0) device open count is 0 (close)
>> >   ModemManager: <debug> (ttyACM0) closing serial port...
>> >   ModemManager: <debug> (ttyACM0) serial port closed
>> >   ModemManager: mm_serial_port_close: assertion `priv->open_count > 0' failed
>> >
>> > The assertion is confusing as the condition is normal. This patch thus turns
>> > the 'priv->open_count > 0' assertion in mm_serial_port_close into a simple
>> > return.
>> > ---
>>
>> I wouldn't say the condition is normal. Each port open request has its
>> corresponding port close request. The only case in which we should not
>> warn about close requests happening to a port with open_count==0 is when
>> the port was forced-closed, which is already handled for what I can see
>> "if (priv->forced_close) return;".
>>
>> Now, I'm not sure in which situation you got that warning, but the
>> warning is indeed useful to detect issues with port open/close count
>> balance... The logs say that the ttyACM0 was forced-close; maybe
>> priv->forced_close wasn't set?
>>
>
> The following call sequence illustrate the problem.
>
> 1. mm_serial_port_close_force calls mm_serial_port_close.
> 2. Before mm_serial_port_close_force even finishes and returns, it
> invokes a response callback of a command in priv->queue
> 3. The response callback completes and frees the associated context,
> which calls mm_serial_port_close_force again
> 4. The assertion is caused by the second call to mm_serial_port_close_force.
>
> mm_serial_port_close_force {
>     ...
>     priv->open_count = 1;
>     mm_serial_port_close (self) {
>         if (priv->forced_close)    // forced_close = FALSE
>             return;
>         g_return_if_fail (priv->open_count > 0);   //  open_count = 1
>
>         priv->open_count--;    // open_count = 0
>
>         ...
>
>         for (i = 0; i < g_queue_get_length (priv->queue); i++) {
>             MMQueueData *item = g_queue_peek_nth (priv->queue, i);
>
>             if (item->callback) {
>                 ....
>                 g_warn_if_fail (MM_SERIAL_PORT_GET_CLASS
> (self)->handle_response != NULL);
>                 error = g_error_new_literal (MM_SERIAL_ERROR,
>                                              MM_SERIAL_ERROR_SEND_FAILED,
>                                              "Serial port is now closed");
>                 ...
>                 MM_SERIAL_PORT_GET_CLASS (self)->handle_response (self,
>                                                                  response,
>                                                                  error,
>                                                                  item->callback,
>
> item->user_data) {
>
>                       // !!! here handle_response will eventually
> triggers the following sequence:
>
>                        at_command_parse_response {
>                            at_command_context_free {
>
>                                mm_serial_port_close (self) {
>                                    if (priv->forced_close)    //
> forced_close = FALSE
>                                       return;
>                                    g_return_if_fail (priv->open_count
>> 0);   //  open_count = 0   --> assertion!
>                                 }
>                           }
>                        }
>
>                 }
>
>                 g_error_free (error);
>                 g_byte_array_free (response, TRUE);
>             }
>             ....
>         }
>
>         }
>     }
>     priv->forced_close = TRUE;
>     ...
> }


More information about the ModemManager-devel mailing list