Imported Upstream version 3.3.3
[debian/amanda] / perl / amglue / source.c
1 /*
2  * Copyright (c) 2008-2012 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21
22 #include "amglue.h"
23
24 /* GSources are tricky to bind to perl for a few reasons:
25  *  - they have a one-way state machine: once attached and detached, they
26  *    cannot be re-attached
27  *  - different "kinds" of GSources require C-level callbacks with
28  *    different signatures
29  *  - an attached GSource should continue running, even if not referenced
30  *    from perl, while a detached GSource should free all its resources
31  *    when no longer referenced.
32  *
33  * To accomplish all of this, this file implements a "glue object" called
34  * amglue_Source.  There are zero or one amglue_Source objects for each
35  * GSource object, so they serve as a place to store "extra" data about a
36  * GSource.  In particular, they store:
37  *  - a pointer to a C callback function that can trigger a Perl callback
38  *  - a pointer to an SV representing the perl callback to run
39  *  - a reference count
40  * Any number of Perl SV's may reference the amglue_Source -- it tracks this
41  * via its reference count.
42  *
43  * Let's look at this arrangement as it follows a typical usage scenario.  The
44  * numbers in brackets are reference counts.
45  *
46  * -- my $src = Amanda::MainLoop::new_foo_source();
47  * GSrc[1] <----) amSrc[1] <---- $src[1] <--- perl-stack
48  *
49  * The lexical $src contains a reference to the amglue_Source object, which is
50  * referencing the underlying GSource object.  Pretty simple.  The amglue_Source
51  * only counts one reference because the GSource isn't yet attached.  Think of
52  * the ')' in the diagram as a weak reference.  If the perl scope were to end
53  * now, all of these objects would be freed immediately.
54  *
55  * -- $src->set_callback(\&cb);
56  *                              ,--> &cb[1]
57  * GMainLoop --> GSrc[2] <---> amSrc[2]
58  *                              ^--- $src[1] <--- perl-stack
59  *
60  * The GSource has been attached, so GMainLoop holds a reference to it.  The
61  * amglue_Source incremented its own reference count, making the previous weak
62  * reference a full reference, because the link from the GSource will be used
63  * when a callback occurs.  The amglue_Source object also keeps a reference to
64  * the callback coderef.
65  *
66  * -- return;
67  *                              ,--> &cb[1]
68  * GMainLoop --> GSrc[2] <---> amSrc[1]
69  *
70  * When the perl scope ends, the lexical $src is freed, reducing the reference
71  * count on the amglue_Source to 1.  At this point, the object is not accessible
72  * from perl, but it is still accessible from the GSource via a callback.
73  *
74  * -- # in callback
75  *                              ,--> &cb[1]
76  * GMainLoop --> GSrc[2] <---> amSrc[2] <--- $self[1] <--- perl-stack
77  *
78  * When the callback is invoked, a reference to the amglue_Source is placed on
79  * the perl stack, so it is once again referenced twice.
80  *
81  * -- $self->remove();
82  *               GSrc[1] <---) amSrc[1] <--- $self[1] <--- perl-stack
83  *
84  * Now the callback itself has called remove().  The amglue_Source object removes
85  * the GSource from the MainLoop and drops its reference to the perl callback, and
86  * decrements its refcount to again weaken the reference from the GSource.  The
87  * amglue_Source is now useless, but since it is still in scope, it remains
88  * allocated and accessible.
89  *
90  * -- return;
91  *
92  * When the callback returns, the last reference to SV is destroyed, reducing
93  * the reference count to the amglue_Source to zero, reducing the reference to
94  * the GSource to zero.  Everything is gone.
95  */
96
97 /* We use a glib 'dataset' to attach an amglue_Source to each GSource
98  * object.  This requires a Quark to describe the kind of data being
99  * attached.
100  *
101  * We define a macro and corresponding global to support access
102  * to our quark.  The compiler will optimize out all but the first
103  * conditional in each function, which is just as we want it. */
104 static GQuark _quark = 0;
105 #define AMGLUE_SOURCE_QUARK \
106     ( _quark?_quark:(_quark = g_quark_from_static_string("amglue_Source")) )
107
108 amglue_Source *
109 amglue_source_get(
110     GSource *gsrc,
111     GSourceFunc callback)
112 {
113     amglue_Source *src;
114     g_assert(gsrc != NULL);
115
116     src = (amglue_Source *)g_dataset_id_get_data(gsrc, AMGLUE_SOURCE_QUARK);
117
118     if (!src)
119         src = amglue_source_new(gsrc, callback);
120     else
121         amglue_source_ref(src);
122
123     return src;
124 }
125
126 amglue_Source *
127 amglue_source_new(
128     GSource *gsrc,
129     GSourceFunc callback)
130 {
131     amglue_Source *src = g_new0(amglue_Source, 1);
132     g_source_ref(gsrc);
133     src->src = gsrc;
134     src->callback = callback;
135     src->state = AMGLUE_SOURCE_NEW;
136     src->refcount = 1;
137     g_dataset_id_set_data(gsrc, AMGLUE_SOURCE_QUARK, (gpointer)src);
138
139     return src;
140 }
141
142 void
143 amglue_source_free(
144     amglue_Source *self)
145 {
146     /* if we're attached, we hold a circular reference to ourselves,
147      * so we shouldn't be at refcount=0 */
148     g_assert(self->state != AMGLUE_SOURCE_ATTACHED);
149     g_assert(self->callback_sv == NULL);
150
151     g_dataset_id_remove_data(self->src, AMGLUE_SOURCE_QUARK);
152     g_source_unref(self->src);
153     g_free(self);
154 }