[Vala] Problem with Closure in Coroutine



Gnome bugzilla is down today, so after the deafening silence on IRC I
figured I might give mail a chance. This function:

========================================================================

    public override async void play_sound( string name, int loop, int
length ) throws FreeSmartphone.Device.AudioError, FreeSmartphone.Error
    {
        PlayingSound sound = sounds[name];
        if ( sound != null )
        {
            throw new
FreeSmartphone.Device.AudioError.ALREADY_PLAYING( "%s is already
playing".printf( name ) );
        }

        var parts = name.split( "." );
        if ( parts.length == 0 )
        {
            throw new FreeSmartphone.Error.INVALID_PARAMETER( "Could not
guess media format; need an extension" );
        }
        var extension = parts[ parts.length - 1 ]; // darn, I miss
negative array indices
        var decoder = decoders[extension];
        assert( decoder != null );

        assert( this != null );

        try
       ERROR:plugin.c:464:_lambda1_: assertion failed: (self != NULL)
Aborted
 {
            var pipeline = Gst.parse_launch( @"filesrc location=\"$name
\" ! $decoder ! alsasink" );
            sound = new PlayingSound( name, loop, length,
(uint32)pipeline );

            Gst.Bus bus = pipeline.get_bus();
            bus.add_watch( ( bus, message ) => {
                assert( this != null );
                return onGstreamerMessage( bus, message, sound );
            } );
            pipeline.set_state( Gst.State.PLAYING );
        }
        catch ( GLib.Error e )
        {
            FsoFramework.theLogger.warning( @"Could not create/launch
GStreamer pipeline: $(e.message)" );
            return;
        }
    }

========================================================================
bails out at runtime with:

ERROR:plugin.c:464:_lambda1_: assertion failed: (self != NULL)
Aborted
========================================================================

The problem seems to be that the data for the closure (_data_->_data2_)
gets unref'ed when the function ends; however Gst is calling the
callback later on and then the instance is 0x0. The C code for this
function is:

========================================================================

static gboolean player_gstreamer_real_play_sound_co
(PlayerGstreamerPlaySoundData* data) {
        switch (data->_state_) {
                default:
                g_assert_not_reached ();
                case 0:
                {
                        data->_data2_ = g_slice_new0 (Block2Data);
                        data->_data2_->_ref_count_ = 1;
                        data->_data2_->self = g_object_ref (data->self);
                        data->_data2_->sound = (FsoDevicePlayingSound*) gee_abstract_map_get
((GeeAbstractMap*) ((FsoDeviceBaseAudioPlayer*) data->self)->sounds,
data->name);
                        if (data->_data2_->sound != NULL) {
                                data->_inner_error_ = (data->_tmp1_ = g_error_new_literal
(FREE_SMARTPHONE_DEVICE_AUDIO_ERROR,
FREE_SMARTPHONE_DEVICE_AUDIO_ERROR_ALREADY_PLAYING, data->_tmp0_ =
g_strdup_printf ("%s is already playing", data->name)), _g_free0
(data->_tmp0_), data->_tmp1_);
                                if (data->_inner_error_ != NULL) {
                                        if ((data->_inner_error_->domain ==
FREE_SMARTPHONE_DEVICE_AUDIO_ERROR) || (data->_inner_error_->domain ==
FREE_SMARTPHONE_ERROR)) {
                                                g_simple_async_result_set_from_error (data->_async_result,
data->_inner_error_);
                                                g_error_free (data->_inner_error_);
                                                block2_data_unref (data->_data2_);
                                                {
                                                        if (data->_state_ == 0) {
                                                                g_simple_async_result_complete_in_idle 
(data->_async_result);
                                                        } else {
                                                                g_simple_async_result_complete 
(data->_async_result);
                                                        }
                                                        g_object_unref (data->_async_result);
                                                        return FALSE;
                                                }
                                        } else {
                                                block2_data_unref (data->_data2_);
                                                g_critical ("file %s: line %d: uncaught error: %s", __FILE__,
__LINE__, data->_inner_error_->message);
                                                g_clear_error (&data->_inner_error_);
                                                return FALSE;
                                        }
                                }
                        }
                        data->parts = (data->_tmp3_ = data->_tmp2_ = g_strsplit (data->name,
".", 0), data->parts_length1 = _vala_array_length (data->_tmp2_),
data->parts_size = data->parts_length1, data->_tmp3_);
                        if (data->parts_length1 == 0) {
                                data->_inner_error_ = g_error_new_literal (FREE_SMARTPHONE_ERROR,
FREE_SMARTPHONE_ERROR_INVALID_PARAMETER, "Could not guess media format;
need an extension");
                                if (data->_inner_error_ != NULL) {
                                        if ((data->_inner_error_->domain ==
FREE_SMARTPHONE_DEVICE_AUDIO_ERROR) || (data->_inner_error_->domain ==
FREE_SMARTPHONE_ERROR)) {
                                                g_simple_async_result_set_from_error (data->_async_result,
data->_inner_error_);
                                                g_error_free (data->_inner_error_);
                                                data->parts = (_vala_array_free (data->parts, 
data->parts_length1,
(GDestroyNotify) g_free), NULL);
                                                block2_data_unref (data->_data2_);
                                                {
                                                        if (data->_state_ == 0) {
                                                                g_simple_async_result_complete_in_idle 
(data->_async_result);
                                                        } else {
                                                                g_simple_async_result_complete 
(data->_async_result);
                                                        }
                                                        g_object_unref (data->_async_result);
                                                        return FALSE;
                                                }
                                        } else {
                                                data->parts = (_vala_array_free (data->parts, 
data->parts_length1,
(GDestroyNotify) g_free), NULL);
                                                block2_data_unref (data->_data2_);
                                                g_critical ("file %s: line %d: uncaught error: %s", __FILE__,
__LINE__, data->_inner_error_->message);
                                                g_clear_error (&data->_inner_error_);
                                                return FALSE;
                                        }
                                }
                        }
                        data->extension = g_strdup (data->parts[data->parts_length1 - 1]);
                        data->decoder = (char*) gee_abstract_map_get ((GeeAbstractMap*)
data->self->priv->decoders, data->extension);
                        g_assert (data->decoder != NULL);
                        g_assert (data->self != NULL);
                        {
                                data->pipeline = (data->_tmp5_ = gst_parse_launch (data->_tmp4_ =
g_strconcat ("filesrc location=\"", string_to_string (data->name), "\" !
", string_to_string (data->decoder), " ! alsasink", NULL),
&data->_inner_error_), _g_free0 (data->_tmp4_), data->_tmp5_);
                                if (data->_inner_error_ != NULL) {
                                        goto __catch1_g_error;
                                        goto __finally1;
                                }
                                data->_data2_->sound = (data->_tmp6_ = fso_device_playing_sound_new
(data->name, data->loop, data->length, (guint32) data->pipeline),
_fso_device_playing_sound_unref0 (data->_data2_->sound), data->_tmp6_);
                                data->bus = gst_element_get_bus (data->pipeline);
                                gst_bus_add_watch (data->bus, __lambda1__gst_bus_func,
data->_data2_);
                                gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
                                _gst_object_unref0 (data->pipeline);
                                _gst_object_unref0 (data->bus);
                        }
                        goto __finally1;
                        __catch1_g_error:
                        {
                                data->e = data->_inner_error_;
                                data->_inner_error_ = NULL;
                                {
                                        fso_framework_logger_warning (fso_framework_theLogger, data->_tmp7_
= g_strconcat ("Could not create/launch GStreamer pipeline: ",
string_to_string (data->e->message), NULL));
                                        _g_free0 (data->_tmp7_);
                                        _g_error_free0 (data->e);
                                        data->parts = (_vala_array_free (data->parts, data->parts_length1,
(GDestroyNotify) g_free), NULL);
                                        _g_free0 (data->extension);
                                        _g_free0 (data->decoder);
                                        block2_data_unref (data->_data2_);
                                        {
                                                if (data->_state_ == 0) {
                                                        g_simple_async_result_complete_in_idle 
(data->_async_result);
                                                } else {
                                                        g_simple_async_result_complete (data->_async_result);
                                                }
                                                g_object_unref (data->_async_result);
                                                return FALSE;
                                        }
                                        _g_error_free0 (data->e);
                                }
                        }
                        __finally1:
                        if (data->_inner_error_ != NULL) {
                                if ((data->_inner_error_->domain ==
FREE_SMARTPHONE_DEVICE_AUDIO_ERROR) || (data->_inner_error_->domain ==
FREE_SMARTPHONE_ERROR)) {
                                        g_simple_async_result_set_from_error (data->_async_result,
data->_inner_error_);
                                        g_error_free (data->_inner_error_);
                                        data->parts = (_vala_array_free (data->parts, data->parts_length1,
(GDestroyNotify) g_free), NULL);
                                        _g_free0 (data->extension);
                                        _g_free0 (data->decoder);
                                        block2_data_unref (data->_data2_);
                                        {
                                                if (data->_state_ == 0) {
                                                        g_simple_async_result_complete_in_idle 
(data->_async_result);
                                                } else {
                                                        g_simple_async_result_complete (data->_async_result);
                                                }
                                                g_object_unref (data->_async_result);
                                                return FALSE;
                                        }
                                } else {
                                        data->parts = (_vala_array_free (data->parts, data->parts_length1,
(GDestroyNotify) g_free), NULL);
                                        _g_free0 (data->extension);
                                        _g_free0 (data->decoder);
                                        block2_data_unref (data->_data2_);
                                        g_critical ("file %s: line %d: uncaught error: %s", __FILE__,
__LINE__, data->_inner_error_->message);
                                        g_clear_error (&data->_inner_error_);
                                        return FALSE;
                                }
                        }
                        data->parts = (_vala_array_free (data->parts, data->parts_length1,
(GDestroyNotify) g_free), NULL);
                        _g_free0 (data->extension);
                        _g_free0 (data->decoder);
***                     block2_data_unref (data->_data2_);
                }
                {
                        if (data->_state_ == 0) {
                                g_simple_async_result_complete_in_idle (data->_async_result);
                        } else {
                                g_simple_async_result_complete (data->_async_result);
                        }
                        g_object_unref (data->_async_result);
                        return FALSE;
                }
        }
}

========================================================================

and the problem seems to be triggered by the line I have marked (***).

Is this a bug in Vala or am I using the closure wrongly?

Thanks,

-- 
:M:




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]