1 /*
2  * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2010 David King <davidk@openismus.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301, USA.
19  */
20 
21 #include <glib/gi18n-lib.h>
22 #include <string.h>
23 #include "gda-thread-blob-op.h"
24 
25 struct _GdaThreadBlobOpPrivate {
26 	GdaThreadWrapper *wrapper;
27 	GdaBlobOp        *wrapped_op;
28 };
29 
30 static void gda_thread_blob_op_class_init (GdaThreadBlobOpClass *klass);
31 static void gda_thread_blob_op_init       (GdaThreadBlobOp *blob,
32 					   GdaThreadBlobOpClass *klass);
33 static void gda_thread_blob_op_dispose   (GObject *object);
34 
35 static glong gda_thread_blob_op_get_length (GdaBlobOp *op);
36 static glong gda_thread_blob_op_read       (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
37 static glong gda_thread_blob_op_write      (GdaBlobOp *op, GdaBlob *blob, glong offset);
38 
39 static GObjectClass *parent_class = NULL;
40 
41 /*
42  * Object init and dispose
43  */
44 GType
_gda_thread_blob_op_get_type(void)45 _gda_thread_blob_op_get_type (void)
46 {
47 	static GType type = 0;
48 
49 	if (G_UNLIKELY (type == 0)) {
50 		static GMutex registering;
51 		static const GTypeInfo info = {
52 			sizeof (GdaThreadBlobOpClass),
53 			(GBaseInitFunc) NULL,
54 			(GBaseFinalizeFunc) NULL,
55 			(GClassInitFunc) gda_thread_blob_op_class_init,
56 			NULL,
57 			NULL,
58 			sizeof (GdaThreadBlobOp),
59 			0,
60 			(GInstanceInitFunc) gda_thread_blob_op_init,
61 			0
62 		};
63 		g_mutex_lock (&registering);
64 		if (type == 0)
65 			type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaThreadBlobOp", &info, 0);
66 		g_mutex_unlock (&registering);
67 	}
68 	return type;
69 }
70 
71 static void
gda_thread_blob_op_init(GdaThreadBlobOp * op,G_GNUC_UNUSED GdaThreadBlobOpClass * klass)72 gda_thread_blob_op_init (GdaThreadBlobOp *op,
73 			   G_GNUC_UNUSED GdaThreadBlobOpClass *klass)
74 {
75 	g_return_if_fail (GDA_IS_THREAD_BLOB_OP (op));
76 
77 	op->priv = g_new0 (GdaThreadBlobOpPrivate, 1);
78 	op->priv->wrapper = NULL;
79 	op->priv->wrapped_op = NULL;
80 }
81 
82 static void
gda_thread_blob_op_class_init(GdaThreadBlobOpClass * klass)83 gda_thread_blob_op_class_init (GdaThreadBlobOpClass *klass)
84 {
85 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
86 	GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass);
87 
88 	parent_class = g_type_class_peek_parent (klass);
89 
90 	object_class->dispose = gda_thread_blob_op_dispose;
91 	blob_class->get_length = gda_thread_blob_op_get_length;
92 	blob_class->read = gda_thread_blob_op_read;
93 	blob_class->write = gda_thread_blob_op_write;
94 }
95 
96 static void
gda_thread_blob_op_dispose(GObject * object)97 gda_thread_blob_op_dispose (GObject * object)
98 {
99 	GdaThreadBlobOp *thop = (GdaThreadBlobOp *) object;
100 
101 	g_return_if_fail (GDA_IS_THREAD_BLOB_OP (thop));
102 
103 	if (thop->priv) {
104 		g_object_unref (thop->priv->wrapped_op);
105 		g_object_unref (thop->priv->wrapper);
106 		g_free (thop->priv);
107 		thop->priv = NULL;
108 	}
109 
110 	parent_class->dispose (object);
111 }
112 
113 GdaBlobOp *
_gda_thread_blob_op_new(GdaThreadWrapper * wrapper,GdaBlobOp * op)114 _gda_thread_blob_op_new (GdaThreadWrapper *wrapper, GdaBlobOp *op)
115 {
116 	GdaThreadBlobOp *thop;
117 
118 	g_return_val_if_fail (GDA_IS_THREAD_WRAPPER (wrapper), NULL);
119 	g_return_val_if_fail (GDA_IS_BLOB_OP (op), NULL);
120 
121 	thop = g_object_new (GDA_TYPE_THREAD_BLOB_OP, NULL);
122 	thop->priv->wrapper = g_object_ref (wrapper);
123 	thop->priv->wrapped_op = g_object_ref (op);
124 
125 	return GDA_BLOB_OP (thop);
126 }
127 
128 
129 /*
130  * Virtual functions
131  */
132 static glong *
sub_thread_blob_op_get_length(GdaBlobOp * wrapped_op,G_GNUC_UNUSED GError ** error)133 sub_thread_blob_op_get_length (GdaBlobOp *wrapped_op, G_GNUC_UNUSED GError **error)
134 {
135 	/* WARNING: function executed in sub thread! */
136 	glong *retptr;
137 
138 	retptr = g_new (glong, 1);
139 	*retptr = gda_blob_op_get_length (wrapped_op);
140 #ifdef GDA_DEBUG_NO
141 	g_print ("/%s() => %ld\n", __FUNCTION__, *retptr);
142 #endif
143 
144 	return retptr;
145 }
146 
147 static glong
gda_thread_blob_op_get_length(GdaBlobOp * op)148 gda_thread_blob_op_get_length (GdaBlobOp *op)
149 {
150 	GdaThreadBlobOp *thop;
151 	glong *ptr, retval;
152 	guint jid;
153 
154 	thop = (GdaThreadBlobOp *) op;
155 	jid = gda_thread_wrapper_execute (thop->priv->wrapper,
156 					  (GdaThreadWrapperFunc) sub_thread_blob_op_get_length,
157 					  thop->priv->wrapped_op, NULL, NULL);
158 	ptr = (glong*) gda_thread_wrapper_fetch_result (thop->priv->wrapper, TRUE, jid, NULL);
159 	retval = *ptr;
160 	g_free (ptr);
161 	return retval;
162 }
163 
164 typedef struct {
165 	GdaBlobOp *op;
166 	GdaBlob *blob;
167 	glong offset;
168 	glong size;
169 } ThreadData;
170 
171 static glong *
sub_thread_blob_op_read(ThreadData * td,G_GNUC_UNUSED GError ** error)172 sub_thread_blob_op_read (ThreadData *td, G_GNUC_UNUSED GError **error)
173 {
174 	/* WARNING: function executed in sub thread! */
175 	glong *retptr;
176 
177 	retptr = g_new (glong, 1);
178 	*retptr = gda_blob_op_read (td->op, td->blob, td->offset, td->size);
179 #ifdef GDA_DEBUG_NO
180 	g_print ("/%s() => %ld\n", __FUNCTION__, *retptr);
181 #endif
182 
183 	return retptr;
184 }
185 
186 static glong
gda_thread_blob_op_read(GdaBlobOp * op,GdaBlob * blob,glong offset,glong size)187 gda_thread_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
188 {
189 	GdaThreadBlobOp *thop;
190 	ThreadData td;
191 	glong *ptr, retval;
192 	guint jid;
193 
194 	thop = (GdaThreadBlobOp *) op;
195 	td.op = thop->priv->wrapped_op;
196 	td.blob = blob;
197 	td.offset = offset;
198 	td.size = size;
199 
200 	jid = gda_thread_wrapper_execute (thop->priv->wrapper,
201 					  (GdaThreadWrapperFunc) sub_thread_blob_op_read,
202 					  &td, NULL, NULL);
203 	ptr = (glong*) gda_thread_wrapper_fetch_result (thop->priv->wrapper, TRUE, jid, NULL);
204 	retval = *ptr;
205 	g_free (ptr);
206 	return retval;
207 }
208 
209 static glong *
sub_thread_blob_op_write(ThreadData * td,G_GNUC_UNUSED GError ** error)210 sub_thread_blob_op_write (ThreadData *td, G_GNUC_UNUSED GError **error)
211 {
212 	/* WARNING: function executed in sub thread! */
213 	glong *retptr;
214 
215 	retptr = g_new (glong, 1);
216 	*retptr = gda_blob_op_write (td->op, td->blob, td->offset);
217 #ifdef GDA_DEBUG_NO
218 	g_print ("/%s() => %ld\n", __FUNCTION__, *retptr);
219 #endif
220 
221 	return retptr;
222 }
223 
224 static glong
gda_thread_blob_op_write(GdaBlobOp * op,GdaBlob * blob,glong offset)225 gda_thread_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
226 {
227 	GdaThreadBlobOp *thop;
228 	ThreadData td;
229 	glong *ptr, retval;
230 	guint jid;
231 
232 	thop = (GdaThreadBlobOp *) op;
233 	td.op = thop->priv->wrapped_op;
234 	td.blob = blob;
235 	td.offset = offset;
236 
237 	jid = gda_thread_wrapper_execute (thop->priv->wrapper,
238 					  (GdaThreadWrapperFunc) sub_thread_blob_op_write,
239 					  &td, NULL, NULL);
240 	ptr = (glong*) gda_thread_wrapper_fetch_result (thop->priv->wrapper, TRUE, jid, NULL);
241 	retval = *ptr;
242 	g_free (ptr);
243 	return retval;
244 }
245