After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 627293 - GOnce support
GOnce support
Status: RESOLVED FIXED
Product: vala
Classification: Core
Component: general
0.9.x
Other Linux
: Normal enhancement
: ---
Assigned To: Vala maintainers
Vala maintainers
Depends on:
Blocks:
 
 
Reported: 2010-08-18 19:03 UTC by Evan Nemerson
Modified: 2014-06-27 19:45 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
0001-Add-bindings-to-GLib.Once.patch (949 bytes, patch)
2013-04-16 12:35 UTC, Maciej (Matthew) Piechotka
none Details | Review
0001-Add-bindings-to-GLib.Once.patch (948 bytes, patch)
2013-04-16 13:02 UTC, Maciej (Matthew) Piechotka
none Details | Review
0001-Add-bindings-to-GLib.Once.patch (1022 bytes, patch)
2013-04-17 12:08 UTC, Maciej (Matthew) Piechotka
none Details | Review
0001-Add-bindings-to-GLib.Once.patch (1.04 KB, patch)
2013-04-17 20:05 UTC, Maciej (Matthew) Piechotka
committed Details | Review

Description Evan Nemerson 2010-08-18 19:03:41 UTC
It would be nice to see support in Vala for executing blocks of code once, likely using GOnce. This could be done either with a keyword somewhat similar to lock (though likely not requiring a variable to operate on), or a way to specify methods which are only executed once.

I don't see a good way to bind GOnce without support for static variables.
Comment 1 Adam Dingle 2012-06-21 17:22:43 UTC
Yes - this would be nice.  See also bug 672094.
Comment 2 Maciej (Matthew) Piechotka 2013-04-16 12:35:03 UTC
Created attachment 241633 [details] [review]
0001-Add-bindings-to-GLib.Once.patch

Fortunately Vala initializes everything to 0 which is just fine for GLib.Once:

class MyClass {
    private GLib.Once<bool> internal1;
    private size_t internal2;
    public void run1 () {
        internal1.once(() => {
            stdout.printf("MyClass.run1(%p)\n", this);
	    return false;
	});
    }
    public void run2 () {
       if (GLib.Once.init_enter ((void **)(&internal2))) {
            stdout.printf("MyClass.run2(%p)\n", this);
            GLib.Once.init_leave((void **)(&internal2), (void *)1);
       }
    }
}

internal GLib.Once<MyClass> once_init1;
internal uint runs1 = 0;

void run1 () {
   unowned MyClass c = once_init1.once(() => {
       stdout.printf("%u\n", ++runs1);
       return new MyClass();
   });
   stdout.printf("%p\n", c);
   c.run1 ();
}

internal MyClass once_init2;
internal uint runs2 = 0;

void run2 () {
   if (GLib.Once.init_enter (&once_init2)) {
       stdout.printf("%u\n", ++runs2);
       GLib.Once.init_leave(&once_init2, new MyClass());
   }
   stdout.printf("%p\n", once_init2);
   once_init2.run2 ();
}

int main() {
    run1 ();
    run1 ();
    stdout.printf("--------------\n");
    run2 ();
    run2 ();
    return 0;
}

Output:

1
0x1e8cc00
MyClass.run1(0x1e8cc00)
0x1e8cc00
--------------
1
0x1e8cc40
MyClass.run2(0x1e8cc40)
0x1e8cc40
Comment 3 Maciej (Matthew) Piechotka 2013-04-16 13:02:21 UTC
Created attachment 241636 [details] [review]
0001-Add-bindings-to-GLib.Once.patch

Update after discussion with Luca about types.
Comment 4 Maciej (Matthew) Piechotka 2013-04-17 12:08:55 UTC
Created attachment 241730 [details] [review]
0001-Add-bindings-to-GLib.Once.patch

Update - the once is not guaranteed to call its argument so it is safer to create separate delegate.
Comment 5 Luca Bruno 2013-04-17 12:29:24 UTC
I still haven't understood what g_once passes to the func, because there's no parse_debug_flags.
Also, what's wrong with ThreadFunc? The scope=async is even good to have here, so that any user data will be freed after the func is called.
Comment 6 Maciej (Matthew) Piechotka 2013-04-17 12:37:16 UTC
(In reply to comment #5)
> I still haven't understood what g_once passes to the func, because there's no
> parse_debug_flags.

Parse_debug_flags from example https://developer.gnome.org/glib/2.36/glib-Threads.html#g-once is just a name of function will be called. Otherwise I have no idea what you're referring to.

> Also, what's wrong with ThreadFunc? The scope=async is even good to have here,
> so that any user data will be freed after the func is called.

GOnce<int> once;

void do_it_once () {
    int value = 0; // value allocated on heap as it is referenced in closure
    once.once (() => {
        stdout.printf("Print it %d time\n", ++value);
    });
}

int main () {
    do_it_once (); // Callback frees the value - OK
    do_it_once (); // Callback is never called
}
Comment 7 Luca Bruno 2013-04-17 12:40:12 UTC
(In reply to comment #6)
> Parse_debug_flags from example
> https://developer.gnome.org/glib/2.36/glib-Threads.html#g-once is just a name
> of function will be called. Otherwise I have no idea what you're referring to.

Yes, and it would have been useful to show at least the signature of the func. So what's the signature of func?

> GOnce<int> once;
> 
> void do_it_once () {
>     int value = 0; // value allocated on heap as it is referenced in closure
>     once.once (() => {
>         stdout.printf("Print it %d time\n", ++value);
>     });
> }
> 
> int main () {
>     do_it_once (); // Callback frees the value - OK
>     do_it_once (); // Callback is never called
> }

Ok makes sense.
Comment 8 Maciej (Matthew) Piechotka 2013-04-17 12:50:29 UTC
(In reply to comment #7)
> (In reply to comment #6)
> > Parse_debug_flags from example
> > https://developer.gnome.org/glib/2.36/glib-Threads.html#g-once is just a name
> > of function will be called. Otherwise I have no idea what you're referring to.
> 
> Yes, and it would have been useful to show at least the signature of the func.
> So what's the signature of func?
> 

Well it is a macro (https://git.gnome.org/browse/glib/tree/glib/gthread.h?id=2.36.1#n238) but underlaying implementation uses GThreadFunc (https://git.gnome.org/browse/glib/tree/glib/gthread.h?id=2.36.1#n228). The difference is that once might not call the callback.
Comment 9 Luca Bruno 2013-04-17 12:52:40 UTC
Patch looks fine to me. I'd like Evan to review it too before landing.
Comment 10 Evan Nemerson 2013-04-17 19:17:52 UTC
It would be nice to have a [CCode (default_value = "G_ONCE_INIT")] on the struct so that it gets initialized with G_ONCE_INIT instead of {0}.  Also, you're missing spaces before the open parenthesis in a few places.
Comment 11 Maciej (Matthew) Piechotka 2013-04-17 20:05:20 UTC
Created attachment 241771 [details] [review]
0001-Add-bindings-to-GLib.Once.patch

Include CCode default_value and missing spaces.
Comment 12 Evan Nemerson 2014-06-27 19:45:08 UTC
commit f5a54052d1f7fb263bb8363934fabdc845f3a934
Author: Maciej Piechotka <uzytkownik2@gmail.com>
Date:   Tue Apr 16 13:53:13 2013 +0200

    Add bindings to GLib.Once