Re: RFC: glocal - automatically freeing memory when it goes out of scope
- From: Mikkel Kamstrup Erlandsen <mikkel kamstrup gmail com>
- To: gtk-devel-list <gtk-devel-list gnome org>
- Subject: Re: RFC: glocal - automatically freeing memory when it goes out of scope
- Date: Sun, 27 May 2012 11:20:14 +0200
On 10 April 2012 11:28, Mikkel Kamstrup Erlandsen
<mikkel kamstrup 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 kamstrup 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__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]