On 10 April 2012 11:28, Mikkel Kamstrup Erlandsen <mikkel.kamst...@canonical.com> wrote: > On 04/04/2012 05:35 AM, Colin Walters wrote: >> >> On Wed, 2011-11-16 at 21:05 +0100, Mikkel Kamstrup Erlandsen wrote: >>> >>> Hi all, >>> >>> I have been looking at gcc's "cleanup" attribute[1] that allows one to >>> specify a callback that will be invoked when a variable goes out of >>> scope. This allows one to play with automatically freeing resources. >> >> >> So this is frankly pretty cool - but we can't make GLib/GTK+ >> dependent on GNU C. > > > Totally agreed. (although cursory research seems to indicate this will work > on clang as well, I realize glib is used with many other compilers) > > >> I could imagine using this in some gcc/Linux-specific parts of GNOME >> though; care to polish up the header, and we could put it somewhere it >> can be shared/reused (not sure where...libegg?) > > > Sure, I have some updates lying around I want to apply as well (fx. Go-style > deferred method calls), then I repost an updated version.
Attached a new version as a late update to this thread, but better than nothing I hope :-) I still haven't gotten around to sticking it in libegg (or even a bug). Sorry! I'll do that when I am more happy with what I have. In any case, here are some updates: - Added glocal_defer(callback, arg): Calls @callback with @arg when leaving the current scope - Add convenience lock/unlock macros for GMutex, GRecMutex, and GRWLock. They grab a given lock and unlock it when leaving the current scope - Renamed to glib-gnuc.h since I find that more appropriate, and better fits with clang using the gnuc profile (for those with those tendencies). Cheers, Mikkel
/* glib-gnuc.h: gcc specific extensions to glib * * Copyright (C) 2011 Canonical Ltd * 2012 Mikkel Kamstrup Erlandsen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * Author: Mikkel Kamstrup Erlandsen <mikkel.kamst...@canonical.com> */ #include <glib.h> #include <glib-object.h> #ifndef __GLIB_GNUC_H__ #define __GLIB_GNUC_H__ #ifndef __GNUC__ #error "This project uses non-standard GNU C extensions and requires 'gcc´ to compile." #endif G_BEGIN_DECLS /** * glocal_string: * * Macro declaring that a null terminated string be automatically freed when it * goes out of scope. For example: * <informalexample><programlisting> * if (print_hello_world) * { * glocal_string gchar *str = g_strdup ("world!"); * g_printf ("Hello %s\n", str); * // at this point 'str´ is automatically freed * } * </programlisting></informalexample> * Beware that if you assign the value of the local string to some other string * that there is no transfer of ownership. The local variable will still be * freed when it goes out of scope. If you want to avoid this you can set the * local variable to %NULL. The following snippet is thus legal: * <informalexample><programlisting> * gchar *snooped_string; * if (print_hello_world) * { * glocal_string gchar *str = g_strdup ("world!"); * g_printf ("Hello %s\n", str); * snooped_string = str; * str = NULL; * // at this point 'str´ is NULL and nothing will happen * } * g_printf ("Woohoo. I just stole the whole %s\n", snooped_string); * g_free (snooped_string); * </programlisting></informalexample> */ #define glocal_string __attribute__ ((cleanup(_glocal_free_str))) static void _glocal_free_str (gchar **strp) { if (strp && *strp) g_free (*strp); } /** * glocal_object: * * Macro declaring that a GObject will be automatically unreferenced when * it goes out of scope. * * Example: * <informalexample><programlisting> * glocal_object GFile *file = g_file_new_for_path ("/tmp"); * glocal_string gchar *basename = g_file_get_basename (file); * g_printf ("Basename is '%s'\n", basename); * * // The two variables file and basename are automatically freed * </programlisting></informalexample> * * If you want to avoid freeing the object when it goes out of scope you can * set the pointer to %NULL. See glocal_string() for an example. */ #define glocal_object __attribute__ ((cleanup(_glocal_unref_object))) static void _glocal_unref_object (void *ptraddr) { GObject **objp = (GObject**) ptraddr; if (objp && *objp) g_object_unref (*objp); } /** * glocal_defer: * @cb: Callback to invoke when leaving the current scope * @arg: A pointer argument to pass to @cb * * Specify a function to call when leaving the current scope. The function * should take a single pointer argument and return void. * * The two arguments must be given as explicit function- and variable names. * You can not pass verbatim constants or expressions. * * You can only defer same pair of @cb and @arg once in each scope. You can, * however, defer the same callback with different arguments, or different * callbacks on the same argument. */ #define glocal_defer(cb, arg) \ void *glocal_deferred_ ## cb ## _ ## arg [2] = { cb, arg }; \ __attribute__ ((cleanup(_glocal_defer))) void **_glocal_deferred_ ## cb ## _ ## arg = glocal_deferred_ ## cb ## _ ## arg static void _glocal_defer (void ***cb_data) { void **_cb_data = *cb_data; void (*cb) (void *) = _cb_data[0]; void *data = _cb_data[1]; cb (data); } /** * glocal_lock_mutex: * @mutex: The mutex to lock * * Convenience macro to lock a #GMutex and unlock it automatically when * leaving the current scope. * * The argument must be given as an explicit pointer variable. You can * not use an expression to this macro. */ #define glocal_lock_mutex(mutex) \ g_mutex_lock (mutex); \ glocal_defer (g_mutex_unlock, mutex) /** * glocal_lock_rec_mutex: * @mutex: The recursive mutex to lock * * Convenience macro to lock a #GRecMutex and unlock it automatically when * leaving the current scope. * * The argument must be given as an explicit pointer variable. You can * not use an expression to this macro. */ #define glocal_lock_rec_mutex(mutex) \ g_rec_mutex_lock (mutex); \ glocal_defer (g_rec_mutex_unlock, mutex) /** * glocal_lock_writer: * @rwlock: The read-write lock to take the writing lock on * * Convenience macro to take the writing lock on a #GRWLock and unlock it * automatically when leaving the current scope. * * The argument must be given as an explicit pointer variable. You can * not use an expression to this macro. */ #define glocal_lock_writer(rwlock) \ g_rw_lock_writer_lock (rwlock); \ glocal_defer (g_rw_lock_writer_unlock, rwlock) /** * glocal_lock_reader: * @rwlock: The read-write lock to take the reading lock on * * Convenience macro to take the reading lock on a #GRWLock and unlock it * automatically when leaving the current scope. * * The argument must be given as an explicit pointer variable. You can * not use an expression to this macro. */ #define glocal_lock_reader(rwlock) \ g_rw_lock_reader_lock (rwlock); \ glocal_defer (g_rw_lock_reader_unlock, rwlock) G_END_DECLS #endif /* __GLIB_GNUC_H__ */
_______________________________________________ gtk-devel-list mailing list gtk-devel-list@gnome.org https://mail.gnome.org/mailman/listinfo/gtk-devel-list