callback arguments and installation



hi,

from http://www.gtk.org/plan/meetings/20060222.txt:

Feb 22 16:27:14 <federico>	in gtkfilesystemunix
Feb 22 16:27:31 <federico>	you have dispatch_get_info_callback(), where the caller must *not* free the file_info

Feb 22 16:27:49 <federico>	you have dispatch_get_folder_callback(), where the caller *must* unref the folder object
Feb 22 16:28:16 <federico>	I don't like that disparity.  All such functions should give the caller's callback something that it *must* unref/free.
Feb 22 16:28:55 <federico>	mclasen: so that we can ref a single instance of each icon instead of having many copies
Feb 22 16:29:18 <kris>	hrm, I think it makes more sense that the dispatch routine would unref/free all stuff it passed to the callback when the callback returns
Feb 22 16:29:29 <kris>	and if the receiver of the callback wants to use that data later on it would ref/copy it
Feb 22 16:30:53 <kris>	but we probably need to match here what the rest of gtk+ does
Feb 22 16:33:30 <federico>	kris: that's another possibility.  In any case, it should be consistent across callbacks.
Feb 22 16:33:43 <kris>	yep

*the* gtk example for this are signal callbacks. in general, if callbacks are
invoked, all arguments/obejcts/handles passed in to it should be kept alive
across the whole invocation. e.g.:

  /* make sure all args stay alive and const across callback invocation */
  char *x= g_strdup (volatile_string);
  GObject *o = g_object_ref (something);
  callback (x, o);
  g_free (x);
  g_object_unref (o);

as a related side note, depending on the API, extra provisions have to
be taken to handle callback modification/removal calls during callback
invocation.
e.g. this code is buggy:

void
foo_set_callback (Foo         *f,
                  FooFunc      ffunc,
                  gpointer     data,
                  GDestroyFunc dfunc)
{
  if (f->dfunc)
    f->dfunc (f->data); /* BAD: callback called with f->dfunc containing old pointer */
  f->ffunc = ffunc;
  f->data = data;
  f->dfunc = dfunc;
}

because the invocation of f->dfunc() might call foo_set_callback() again
(not unlikely, especially if f->dfunc() calls library routines that have
their own cleanup routines, do unref()s, etc.)

instead, the following logic should be used:

void
foo_set_callback (Foo         *f,
                  FooFunc      ffunc,
                  gpointer     data,
                  GDestroyFunc dfunc)
{
  GDestroyFunc odestroy = f->dfunc;
  gpointer odata = f->data;
  f->ffunc = ffunc;
  f->data = data;
  f->dfunc = dfunc;
  if (odestroy)
    odestroy (odata); /* GOOD: foo_set_callback() may safely be called recursively */
}

---
ciaoTJ



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