tracker-0.16.2/src/tracker-writeback/tracker-writeback.c

Location Tool Test ID Function Issue
tracker-writeback.c:629:3 gcc deprecated-declarations handle_method_call_perform_writeback 'g_io_scheduler_push_job' is deprecated (declared at /usr/include/glib-2.0/gio/gioscheduler.h:36): Use '"GThreadPool or g_task_run_in_thread"' instead
  1 /*
  2  * Copyright (C) 2011, Nokia <ivan.frade@nokia.com>
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU General Public
 15  * License along with this library; if not, write to the
 16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 17  * Boston, MA  02110-1301, USA.
 18  */
 19 
 20 #include "tracker-writeback.h"
 21 #include "tracker-writeback-module.h"
 22 
 23 #include <libtracker-common/tracker-common.h>
 24 #include <libtracker-miner/tracker-miner.h>
 25 #include <libtracker-sparql/tracker-sparql.h>
 26 
 27 #include <gio/gio.h>
 28 
 29 #ifdef STAYALIVE_ENABLE_TRACE
 30 #warning Stayalive traces enabled
 31 #endif /* STAYALIVE_ENABLE_TRACE */
 32 
 33 #ifdef THREAD_ENABLE_TRACE
 34 #warning Controller thread traces enabled
 35 #endif /* THREAD_ENABLE_TRACE */
 36 
 37 typedef struct {
 38 	TrackerController *controller;
 39 	GCancellable *cancellable;
 40 	GDBusMethodInvocation *invocation;
 41 	TrackerDBusRequest *request;
 42 	gchar *subject;
 43 	GPtrArray *results;
 44 	TrackerSparqlConnection *connection;
 45 	GList *writeback_handlers;
 46 	guint cancel_id;
 47 	GError *error;
 48 } WritebackData;
 49 
 50 typedef struct {
 51 	GMainContext *context;
 52 	GMainLoop *main_loop;
 53 
 54 	TrackerStorage *storage;
 55 
 56 	GDBusConnection *d_connection;
 57 	GDBusNodeInfo *introspection_data;
 58 	guint registration_id;
 59 	guint bus_name_id;
 60 
 61 	GList *ongoing_tasks;
 62 
 63 	guint shutdown_timeout;
 64 	GSource *shutdown_source;
 65 
 66 #if GLIB_CHECK_VERSION (2,31,0)
 67 	GCond initialization_cond;
 68 	GMutex initialization_mutex, mutex;
 69 #else
 70 	GCond *initialization_cond;
 71 	GMutex *initialization_mutex, *mutex;
 72 #endif
 73 	GError *initialization_error;
 74 
 75 	guint initialized : 1;
 76 
 77 	GHashTable *modules;
 78 	TrackerSparqlConnection *connection;
 79 	WritebackData *current;
 80 } TrackerControllerPrivate;
 81 
 82 #define TRACKER_WRITEBACK_SERVICE   "org.freedesktop.Tracker1.Writeback"
 83 #define TRACKER_WRITEBACK_PATH      "/org/freedesktop/Tracker1/Writeback"
 84 #define TRACKER_WRITEBACK_INTERFACE "org.freedesktop.Tracker1.Writeback"
 85 
 86 static const gchar *introspection_xml =
 87 	"<node>"
 88 	"  <interface name='org.freedesktop.Tracker1.Writeback'>"
 89 	"    <method name='GetPid'>"
 90 	"      <arg type='i' name='value' direction='out' />"
 91 	"    </method>"
 92 	"    <method name='PerformWriteback'>"
 93 	"      <arg type='s' name='subject' direction='in' />"
 94 	"      <arg type='as' name='rdf_types' direction='in' />"
 95 	"      <arg type='aas' name='results' direction='in' />"
 96 	"    </method>"
 97 	"    <method name='CancelTasks'>"
 98 	"      <arg type='as' name='subjects' direction='in' />"
 99 	"    </method>"
100 	"  </interface>"
101 	"</node>";
102 
103 enum {
104 	PROP_0,
105 	PROP_SHUTDOWN_TIMEOUT,
106 };
107 
108 static void     tracker_controller_initable_iface_init  (GInitableIface     *iface);
109 static gboolean tracker_controller_dbus_start           (TrackerController  *controller,
110                                                          GError            **error);
111 static void     tracker_controller_dbus_stop            (TrackerController  *controller);
112 static gboolean tracker_controller_start                (TrackerController  *controller,
113                                                          GError            **error);
114 
115 G_DEFINE_TYPE_WITH_CODE (TrackerController, tracker_controller, G_TYPE_OBJECT,
116                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
117                                                 tracker_controller_initable_iface_init));
118 
119 static gboolean
120 tracker_controller_initable_init (GInitable     *initable,
121                                   GCancellable  *cancellable,
122                                   GError       **error)
123 {
124 	return tracker_controller_start (TRACKER_CONTROLLER (initable), error);
125 }
126 
127 static void
128 tracker_controller_initable_iface_init (GInitableIface *iface)
129 {
130 	iface->init = tracker_controller_initable_init;
131 }
132 
133 static void
134 tracker_controller_finalize (GObject *object)
135 {
136 	TrackerControllerPrivate *priv;
137 	TrackerController *controller;
138 
139 	controller = TRACKER_CONTROLLER (object);
140 	priv = controller->priv;
141 
142 	if (priv->shutdown_source) {
143 		g_source_destroy (priv->shutdown_source);
144 		priv->shutdown_source = NULL;
145 	}
146 
147 	tracker_controller_dbus_stop (controller);
148 
149 	g_object_unref (priv->storage);
150 	g_hash_table_unref (priv->modules);
151 
152 	g_main_loop_unref (priv->main_loop);
153 	g_main_context_unref (priv->context);
154 
155 #if GLIB_CHECK_VERSION (2,31,0)
156 	g_cond_clear (&priv->initialization_cond);
157 	g_mutex_clear (&priv->initialization_mutex);
158 	g_mutex_clear (&priv->mutex);
159 #else
160 	g_cond_free (priv->initialization_cond);
161 	g_mutex_free (priv->initialization_mutex);
162 	g_mutex_free (priv->mutex);
163 #endif
164 
165 	G_OBJECT_CLASS (tracker_controller_parent_class)->finalize (object);
166 }
167 
168 static void
169 tracker_controller_get_property (GObject    *object,
170                                  guint       param_id,
171                                  GValue     *value,
172                                  GParamSpec *pspec)
173 {
174 	TrackerControllerPrivate *priv = TRACKER_CONTROLLER (object)->priv;
175 
176 	switch (param_id) {
177 	case PROP_SHUTDOWN_TIMEOUT:
178 		g_value_set_uint (value, priv->shutdown_timeout);
179 		break;
180 	}
181 }
182 
183 static void
184 tracker_controller_set_property (GObject      *object,
185                                  guint         param_id,
186                                  const GValue *value,
187                                  GParamSpec   *pspec)
188 {
189 	TrackerControllerPrivate *priv = TRACKER_CONTROLLER (object)->priv;
190 
191 	switch (param_id) {
192 	case PROP_SHUTDOWN_TIMEOUT:
193 		priv->shutdown_timeout = g_value_get_uint (value);
194 		break;
195 	}
196 }
197 
198 static void
199 tracker_controller_class_init (TrackerControllerClass *klass)
200 {
201 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
202 
203 	object_class->finalize = tracker_controller_finalize;
204 	object_class->get_property = tracker_controller_get_property;
205 	object_class->set_property = tracker_controller_set_property;
206 
207 	g_object_class_install_property (object_class,
208 	                                 PROP_SHUTDOWN_TIMEOUT,
209 	                                 g_param_spec_uint ("shutdown-timeout",
210 	                                                    "Shutdown timeout",
211 	                                                    "Shutdown timeout, 0 to disable",
212 	                                                    0, 1000, 0,
213 	                                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
214 
215 	g_type_class_add_private (object_class, sizeof (TrackerControllerPrivate));
216 }
217 
218 static void
219 task_cancellable_cancelled_cb (GCancellable  *cancellable,
220                                WritebackData *data)
221 {
222 	TrackerControllerPrivate *priv;
223 
224 	priv = data->controller->priv;
225 
226 #if GLIB_CHECK_VERSION (2,31,0)
227 	g_mutex_lock (&priv->mutex);
228 #else
229 	g_mutex_lock (priv->mutex);
230 #endif
231 
232 	if (priv->current == data) {
233 		g_message ("Cancelled writeback task for '%s' was currently being "
234 		           "processed, _exit()ing immediately",
235 		           data->subject);
236 		_exit (0);
237 	}
238 
239 #if GLIB_CHECK_VERSION (2,31,0)
240 	g_mutex_unlock (&priv->mutex);
241 #else
242 	g_mutex_unlock (priv->mutex);
243 #endif
244 }
245 
246 
247 static WritebackData *
248 writeback_data_new (TrackerController       *controller,
249                     GList                   *writeback_handlers,
250                     TrackerSparqlConnection *connection,
251                     const gchar             *subject,
252                     GPtrArray               *results,
253                     GDBusMethodInvocation   *invocation,
254                     TrackerDBusRequest      *request)
255 {
256 	WritebackData *data;
257 
258 	data = g_slice_new (WritebackData);
259 	data->cancellable = g_cancellable_new ();
260 	data->controller = g_object_ref (controller);
261 	data->subject = g_strdup (subject);
262 	data->results = g_ptr_array_ref (results);
263 	data->invocation = invocation;
264 	data->connection = g_object_ref (connection);
265 	data->writeback_handlers = writeback_handlers;
266 	data->request = request;
267 	data->error = NULL;
268 
269 	data->cancel_id = g_cancellable_connect (data->cancellable,
270 	                                         G_CALLBACK (task_cancellable_cancelled_cb),
271 	                                         data, NULL);
272 
273 	return data;
274 }
275 
276 static void
277 writeback_data_free (WritebackData *data)
278 {
279 	/* We rely on data->invocation being freed through
280 	 * the g_dbus_method_invocation_return_* methods
281 	 */
282 	g_cancellable_disconnect (data->cancellable, data->cancel_id);
283 	g_free (data->subject);
284 	g_object_unref (data->connection);
285 	g_ptr_array_unref (data->results);
286 	g_object_unref (data->cancellable);
287 
288 	g_list_foreach (data->writeback_handlers, (GFunc) g_object_unref, NULL);
289 	g_list_free (data->writeback_handlers);
290 
291 	if (data->error) {
292 		g_error_free (data->error);
293 	}
294 	g_slice_free (WritebackData, data);
295 }
296 
297 static void
298 cancel_tasks (TrackerController *controller,
299               const gchar       *subject,
300               GFile             *file)
301 {
302 	TrackerControllerPrivate *priv;
303 	GList *elem;
304 
305 	priv = controller->priv;
306 
307 	for (elem = priv->ongoing_tasks; elem; elem = elem->next) {
308 		WritebackData *data = elem->data;
309 
310 		if (g_strcmp0 (subject, data->subject) == 0) {
311 			g_message ("Cancelling not yet processed task ('%s')",
312 			           data->subject);
313 			g_cancellable_cancel (data->cancellable);
314 		}
315 
316 		if (file) {
317 			guint i;
318 			for (i = 0; i < data->results->len; i++) {
319 				GStrv row = g_ptr_array_index (data->results, i);
320 				if (row[0] != NULL) {
321 					GFile *task_file;
322 					task_file = g_file_new_for_uri (row[0]);
323 					if (g_file_equal (task_file, file) ||
324 					    g_file_has_prefix (task_file, file)) {
325 						/* Mount path contains some file being processed */
326 						g_message ("Cancelling task ('%s')", row[0]);
327 						g_cancellable_cancel (data->cancellable);
328 					}
329 					g_object_unref (task_file);
330 				}
331 			}
332 		}
333 	}
334 }
335 
336 static void
337 mount_point_removed_cb (TrackerStorage *storage,
338                         const gchar    *uuid,
339                         const gchar    *mount_point,
340                         gpointer        user_data)
341 {
342 	GFile *mount_file;
343 
344 	mount_file = g_file_new_for_path (mount_point);
345 	cancel_tasks (TRACKER_CONTROLLER (user_data), NULL, mount_file);
346 	g_object_unref (mount_file);
347 }
348 
349 static gboolean
350 reset_shutdown_timeout_cb (gpointer user_data)
351 {
352 	TrackerControllerPrivate *priv;
353 
354 #ifdef STAYALIVE_ENABLE_TRACE
355 	g_debug ("Stayalive --- time has expired");
356 #endif /* STAYALIVE_ENABLE_TRACE */
357 
358 	g_message ("Shutting down due to no activity");
359 
360 	priv = TRACKER_CONTROLLER (user_data)->priv;
361 	g_main_loop_quit (priv->main_loop);
362 
363 	return FALSE;
364 }
365 
366 static void
367 reset_shutdown_timeout (TrackerController *controller)
368 {
369 	TrackerControllerPrivate *priv;
370 	GSource *source;
371 
372 	priv = controller->priv;
373 
374 	if (priv->shutdown_timeout == 0) {
375 		return;
376 	}
377 
378 #ifdef STAYALIVE_ENABLE_TRACE
379 	g_debug ("Stayalive --- (Re)setting timeout");
380 #endif /* STAYALIVE_ENABLE_TRACE */
381 
382 	if (priv->shutdown_source) {
383 		g_source_destroy (priv->shutdown_source);
384 		priv->shutdown_source = NULL;
385 	}
386 
387 	source = g_timeout_source_new_seconds (priv->shutdown_timeout);
388 	g_source_set_callback (source,
389 	                       reset_shutdown_timeout_cb,
390 	                       controller, NULL);
391 
392 	g_source_attach (source, priv->context);
393 	priv->shutdown_source = source;
394 }
395 
396 static void
397 tracker_controller_init (TrackerController *controller)
398 {
399 	TrackerControllerPrivate *priv;
400 
401 	priv = controller->priv = G_TYPE_INSTANCE_GET_PRIVATE (controller,
402 	                                                       TRACKER_TYPE_CONTROLLER,
403 	                                                       TrackerControllerPrivate);
404 
405 	priv->context = g_main_context_new ();
406 	priv->main_loop = g_main_loop_new (priv->context, FALSE);
407 
408 	priv->storage = tracker_storage_new ();
409 	g_signal_connect (priv->storage, "mount-point-removed",
410 	                  G_CALLBACK (mount_point_removed_cb), controller);
411 
412 #if GLIB_CHECK_VERSION (2,31,0)
413 	g_cond_init (&priv->initialization_cond);
414 	g_mutex_init (&priv->initialization_mutex);
415 	g_mutex_init (&priv->mutex);
416 #else
417 	priv->initialization_cond = g_cond_new ();
418 	priv->initialization_mutex = g_mutex_new ();
419 	priv->mutex = g_mutex_new ();
420 #endif
421 }
422 
423 static void
424 handle_method_call_get_pid (TrackerController     *controller,
425                             GDBusMethodInvocation *invocation,
426                             GVariant              *parameters)
427 {
428 	TrackerDBusRequest *request;
429 	pid_t value;
430 
431 	request = tracker_g_dbus_request_begin (invocation,
432 	                                        "%s()",
433 	                                        __FUNCTION__);
434 
435 	reset_shutdown_timeout (controller);
436 	value = getpid ();
437 	tracker_dbus_request_debug (request,
438 	                            "PID is %d",
439 	                            value);
440 
441 	tracker_dbus_request_end (request, NULL);
442 
443 	g_dbus_method_invocation_return_value (invocation,
444 	                                       g_variant_new ("(i)", (gint) value));
445 }
446 
447 static gboolean
448 perform_writeback_cb (gpointer user_data)
449 {
450 	TrackerControllerPrivate *priv;
451 	WritebackData *data;
452 
453 	data = user_data;
454 	priv = data->controller->priv;
455 	priv->ongoing_tasks = g_list_remove (priv->ongoing_tasks, data);
456 
457 	if (data->error == NULL) {
458 		g_dbus_method_invocation_return_value (data->invocation, NULL);
459 	} else {
460 		g_dbus_method_invocation_return_gerror (data->invocation, data->error);
461 	}
462 
463 	tracker_dbus_request_end (data->request, NULL);
464 
465 #if GLIB_CHECK_VERSION (2,31,0)
466 	g_mutex_lock (&priv->mutex);
467 	priv->current = NULL;
468 	g_mutex_unlock (&priv->mutex);
469 #else
470 	g_mutex_lock (priv->mutex);
471 	priv->current = NULL;
472 	g_mutex_unlock (priv->mutex);
473 #endif
474 
475 	writeback_data_free (data);
476 
477 	return FALSE;
478 }
479 
480 static gboolean
481 sparql_rdf_types_match (const gchar * const *module_types,
482                         const gchar * const *rdf_types)
483 {
484 	guint n;
485 
486 	for (n = 0; rdf_types[n] != NULL; n++) {
487 		guint i;
488 
489 		for (i = 0; module_types[i] != NULL; i++) {
490 			if (g_strcmp0 (module_types[i], rdf_types[n]) == 0) {
491 				return TRUE;
492 			}
493 		}
494 	}
495 
496 	return FALSE;
497 }
498 
499 static gboolean
500 io_writeback_job (GIOSchedulerJob *job,
501                   GCancellable    *cancellable,
502                   gpointer         user_data)
503 {
504 	WritebackData *data = user_data;
505 	TrackerControllerPrivate *priv = data->controller->priv;
506 	GError *error = NULL;
507 	gboolean handled = FALSE;
508 	GList *writeback_handlers;
509 
510 #if GLIB_CHECK_VERSION (2,31,0)
511 	g_mutex_lock (&priv->mutex);
512 	priv->current = data;
513 	g_mutex_unlock (&priv->mutex);
514 #else
515 	g_mutex_lock (priv->mutex);
516 	priv->current = data;
517 	g_mutex_unlock (priv->mutex);
518 #endif
519 
520 	writeback_handlers = data->writeback_handlers;
521 
522 	while (writeback_handlers) {
523 		handled |= tracker_writeback_update_metadata (writeback_handlers->data,
524 		                                              data->results,
525 		                                              data->connection,
526 		                                              data->cancellable,
527 		                                              (error) ? NULL : &error);
528 		writeback_handlers = writeback_handlers->next;
529 	}
530 
531 	if (!handled) {
532 		if (error) {
533 			data->error = error;
534 		} else {
535 			g_set_error_literal (&data->error,
536 			                     TRACKER_DBUS_ERROR,
537 			                     TRACKER_DBUS_ERROR_UNSUPPORTED,
538 			                     "No writeback modules handled "
539 			                     "successfully this file");
540 		}
541 	} else {
542 		g_clear_error (&error);
543 	}
544 
545 	g_idle_add (perform_writeback_cb, data);
546 
547 	return FALSE;
548 }
549 
550 static void
551 handle_method_call_perform_writeback (TrackerController     *controller,
552                                       GDBusMethodInvocation *invocation,
553                                       GVariant              *parameters)
554 {
555 	TrackerControllerPrivate *priv;
556 	TrackerDBusRequest *request;
557 	const gchar *subject;
558 	GPtrArray *results = NULL;
559 	GHashTableIter iter;
560 	gpointer key, value;
561 	GVariantIter *iter1, *iter2, *iter3;
562 	GArray *rdf_types_array;
563 	GStrv rdf_types;
564 	gchar *rdf_type = NULL;
565 	GList *writeback_handlers = NULL;
566 	WritebackData *data;
567 
568 	priv = controller->priv;
569 
570 	results = g_ptr_array_new_with_free_func ((GDestroyNotify) g_strfreev);
571 	g_variant_get (parameters, "(&sasaas)", &subject, &iter1, &iter2);
572 
573 	rdf_types_array = g_array_new (TRUE, TRUE, sizeof (gchar *));
574 	while (g_variant_iter_loop (iter1, "&s", &rdf_type)) {
575 		g_array_append_val (rdf_types_array, rdf_type);
576 	}
577 
578 	rdf_types = (GStrv) rdf_types_array->data;
579 	g_array_free (rdf_types_array, FALSE);
580 
581 	while (g_variant_iter_loop (iter2, "as", &iter3)) {
582 		GArray *row_array = g_array_new (TRUE, TRUE, sizeof (gchar *));
583 		gchar *cell = NULL;
584 
585 		while (g_variant_iter_loop (iter3, "&s", &cell)) {
586 			g_array_append_val (row_array, cell);
587 		}
588 
589 		g_ptr_array_add (results, row_array->data);
590 		g_array_free (row_array, FALSE);
591 	}
592 
593 	g_variant_iter_free (iter1);
594 	g_variant_iter_free (iter2);
595 
596 	reset_shutdown_timeout (controller);
597 	request = tracker_dbus_request_begin (NULL, "%s (%s)", __FUNCTION__, subject);
598 
599 	g_hash_table_iter_init (&iter, priv->modules);
600 
601 	while (g_hash_table_iter_next (&iter, &key, &value)) {
602 		TrackerWritebackModule *module;
603 		const gchar * const *module_types;
604 
605 		module = value;
606 		module_types = tracker_writeback_module_get_rdf_types (module);
607 
608 		if (sparql_rdf_types_match (module_types, (const gchar * const *) rdf_types)) {
609 			TrackerWriteback *writeback;
610 
611 			g_message ("  Updating metadata for subject:'%s' using module:'%s'",
612 			           subject,
613 			           module->name);
614 
615 			writeback = tracker_writeback_module_create (module);
616 			writeback_handlers = g_list_prepend (writeback_handlers, writeback);
617 		}
618 	}
619 
620 	if (writeback_handlers != NULL) {
621 		data = writeback_data_new (controller,
622 		                           writeback_handlers,
623 		                           priv->connection,
624 		                           subject,
625 		                           results,
626 		                           invocation,
627 		                           request);
628 
629 		g_io_scheduler_push_job (io_writeback_job, data, NULL, 0,
'g_io_scheduler_push_job' is deprecated (declared at /usr/include/glib-2.0/gio/gioscheduler.h:36): Use '"GThreadPool or g_task_run_in_thread"' instead
(emitted by gcc)
630 data->cancellable); 631 } else { 632 g_dbus_method_invocation_return_error (invocation, 633 TRACKER_DBUS_ERROR, 634 TRACKER_DBUS_ERROR_UNSUPPORTED, 635 "No module for rdf types"); 636 } 637 638 g_free (rdf_types); 639 } 640 641 static void 642 handle_method_call_cancel_tasks (TrackerController *controller, 643 GDBusMethodInvocation *invocation, 644 GVariant *parameters) 645 { 646 TrackerDBusRequest *request; 647 gchar **subjects; 648 gint i; 649 650 #ifdef THREAD_ENABLE_TRACE 651 g_debug ("Thread:%p (Controller) --> Got Tasks cancellation request", 652 g_thread_self ()); 653 #endif /* THREAD_ENABLE_TRACE */ 654 655 656 g_variant_get (parameters, "(^as)", &subjects); 657 658 request = tracker_dbus_request_begin (NULL, "%s (%s, ...)", __FUNCTION__, subjects[0]); 659 660 for (i = 0; subjects[i] != NULL; i++) { 661 cancel_tasks (controller, subjects[i], NULL); 662 } 663 664 g_strfreev (subjects); 665 tracker_dbus_request_end (request, NULL); 666 g_dbus_method_invocation_return_value (invocation, NULL); 667 } 668 669 static void 670 handle_method_call (GDBusConnection *connection, 671 const gchar *sender, 672 const gchar *object_path, 673 const gchar *interface_name, 674 const gchar *method_name, 675 GVariant *parameters, 676 GDBusMethodInvocation *invocation, 677 gpointer user_data) 678 { 679 TrackerController *controller = user_data; 680 681 if (g_strcmp0 (method_name, "GetPid") == 0) { 682 handle_method_call_get_pid (controller, invocation, parameters); 683 } else if (g_strcmp0 (method_name, "PerformWriteback") == 0) { 684 handle_method_call_perform_writeback (controller, invocation, parameters); 685 } else if (g_strcmp0 (method_name, "CancelTasks") == 0) { 686 handle_method_call_cancel_tasks (controller, invocation, parameters); 687 } else { 688 g_warning ("Unknown method '%s' called", method_name); 689 } 690 } 691 692 static void 693 controller_notify_main_thread (TrackerController *controller, 694 GError *error) 695 { 696 TrackerControllerPrivate *priv; 697 698 priv = controller->priv; 699 700 #if GLIB_CHECK_VERSION (2,31,0) 701 g_mutex_lock (&priv->initialization_mutex); 702 #else 703 g_mutex_lock (priv->initialization_mutex); 704 #endif 705 706 priv->initialized = TRUE; 707 priv->initialization_error = error; 708 709 /* Notify about the initialization */ 710 #if GLIB_CHECK_VERSION (2,31,0) 711 g_cond_signal (&priv->initialization_cond); 712 g_mutex_unlock (&priv->initialization_mutex); 713 #else 714 g_cond_signal (priv->initialization_cond); 715 g_mutex_unlock (priv->initialization_mutex); 716 #endif 717 } 718 719 static void 720 bus_name_acquired_cb (GDBusConnection *connection, 721 const gchar *name, 722 gpointer user_data) 723 { 724 controller_notify_main_thread (TRACKER_CONTROLLER (user_data), NULL); 725 } 726 727 static void 728 bus_name_vanished_cb (GDBusConnection *connection, 729 const gchar *name, 730 gpointer user_data) 731 { 732 TrackerController *controller; 733 TrackerControllerPrivate *priv; 734 735 controller = user_data; 736 priv = controller->priv; 737 738 if (!priv->initialized) { 739 GError *error; 740 741 error = g_error_new_literal (TRACKER_DBUS_ERROR, 0, 742 "Could not acquire bus name, " 743 "perhaps it's already taken?"); 744 controller_notify_main_thread (controller, error); 745 } else { 746 /* We're already in control of the program 747 * lifetime, so just quit the mainloop 748 */ 749 g_main_loop_quit (priv->main_loop); 750 } 751 } 752 753 static gboolean 754 tracker_controller_dbus_start (TrackerController *controller, 755 GError **error) 756 { 757 TrackerControllerPrivate *priv; 758 GError *err = NULL; 759 GDBusInterfaceVTable interface_vtable = { 760 handle_method_call, 761 NULL, NULL 762 }; 763 764 priv = controller->priv; 765 766 priv->connection = tracker_sparql_connection_get (NULL, &err); 767 768 if (!priv->connection) { 769 g_propagate_error (error, err); 770 return FALSE; 771 } 772 773 priv->d_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &err); 774 775 if (!priv->d_connection) { 776 g_propagate_error (error, err); 777 return FALSE; 778 } 779 780 priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &err); 781 if (!priv->introspection_data) { 782 g_propagate_error (error, err); 783 return FALSE; 784 } 785 786 g_message ("Registering D-Bus object..."); 787 g_message (" Path:'" TRACKER_WRITEBACK_PATH "'"); 788 g_message (" Object Type:'%s'", G_OBJECT_TYPE_NAME (controller)); 789 790 priv->registration_id = 791 g_dbus_connection_register_object (priv->d_connection, 792 TRACKER_WRITEBACK_PATH, 793 priv->introspection_data->interfaces[0], 794 &interface_vtable, 795 controller, 796 NULL, 797 &err); 798 799 if (err) { 800 g_critical ("Could not register the D-Bus object "TRACKER_WRITEBACK_PATH", %s", 801 err ? err->message : "no error given."); 802 g_propagate_error (error, err); 803 return FALSE; 804 } 805 806 priv->bus_name_id = 807 g_bus_own_name_on_connection (priv->d_connection, 808 TRACKER_WRITEBACK_SERVICE, 809 G_BUS_NAME_OWNER_FLAGS_NONE, 810 bus_name_acquired_cb, 811 bus_name_vanished_cb, 812 controller, NULL); 813 814 if (err) { 815 g_critical ("Could not own the D-Bus name "TRACKER_WRITEBACK_SERVICE", %s", 816 err ? err->message : "no error given."); 817 g_propagate_error (error, err); 818 return FALSE; 819 } 820 821 return TRUE; 822 } 823 824 static void 825 tracker_controller_dbus_stop (TrackerController *controller) 826 { 827 TrackerControllerPrivate *priv; 828 829 priv = controller->priv; 830 831 if (priv->registration_id != 0) { 832 g_dbus_connection_unregister_object (priv->d_connection, 833 priv->registration_id); 834 } 835 836 if (priv->bus_name_id != 0) { 837 g_bus_unown_name (priv->bus_name_id); 838 } 839 840 if (priv->introspection_data) { 841 g_dbus_node_info_unref (priv->introspection_data); 842 } 843 844 if (priv->d_connection) { 845 g_object_unref (priv->d_connection); 846 } 847 848 if (priv->connection) { 849 g_object_unref (priv->connection); 850 } 851 } 852 853 TrackerController * 854 tracker_controller_new (guint shutdown_timeout, 855 GError **error) 856 { 857 return g_initable_new (TRACKER_TYPE_CONTROLLER, 858 NULL, error, 859 "shutdown-timeout", shutdown_timeout, 860 NULL); 861 } 862 863 static gpointer 864 tracker_controller_thread_func (gpointer user_data) 865 { 866 TrackerController *controller; 867 TrackerControllerPrivate *priv; 868 GError *error = NULL; 869 870 #ifdef THREAD_ENABLE_TRACE 871 g_debug ("Thread:%p (Controller) --- Created, dispatching...", 872 g_thread_self ()); 873 #endif /* THREAD_ENABLE_TRACE */ 874 875 controller = user_data; 876 priv = controller->priv; 877 g_main_context_push_thread_default (priv->context); 878 879 reset_shutdown_timeout (controller); 880 881 if (!tracker_controller_dbus_start (controller, &error)) { 882 /* Error has been filled in, so we return 883 * in this thread. The main thread will be 884 * notified about the error and exit. 885 */ 886 controller_notify_main_thread (controller, error); 887 return NULL; 888 } 889 890 g_main_loop_run (priv->main_loop); 891 892 #ifdef THREAD_ENABLE_TRACE 893 g_debug ("Thread:%p (Controller) --- Shutting down...", 894 g_thread_self ()); 895 #endif /* THREAD_ENABLE_TRACE */ 896 897 g_object_unref (controller); 898 899 /* This is where we exit, be it 900 * either through umount events on monitored 901 * files' volumes or the timeout being reached 902 */ 903 exit (0); 904 return NULL; 905 } 906 907 static gboolean 908 tracker_controller_start (TrackerController *controller, 909 GError **error) 910 { 911 TrackerControllerPrivate *priv; 912 GList *modules; 913 914 priv = controller->priv; 915 916 priv->modules = g_hash_table_new_full (g_str_hash, 917 g_str_equal, 918 (GDestroyNotify) g_free, 919 NULL); 920 921 modules = tracker_writeback_modules_list (); 922 923 while (modules) { 924 TrackerWritebackModule *module; 925 const gchar *path; 926 927 path = modules->data; 928 module = tracker_writeback_module_get (path); 929 930 if (module) { 931 g_hash_table_insert (priv->modules, g_strdup (path), module); 932 } 933 934 modules = modules->next; 935 } 936 937 #if GLIB_CHECK_VERSION (2,31,0) 938 { 939 GThread *thread; 940 941 thread = g_thread_try_new ("controller", 942 tracker_controller_thread_func, 943 controller, 944 error); 945 if (!thread) 946 return FALSE; 947 948 /* We don't want to join it, so just unref the GThread */ 949 g_thread_unref (thread); 950 } 951 #else 952 if (!g_thread_create (tracker_controller_thread_func, 953 controller, FALSE, error)) { 954 return FALSE; 955 } 956 #endif 957 958 959 #ifdef THREAD_ENABLE_TRACE 960 g_debug ("Thread:%p (Controller) --- Waiting for controller thread to initialize...", 961 g_thread_self ()); 962 #endif /* THREAD_ENABLE_TRACE */ 963 964 /* Wait for the controller thread to notify initialization */ 965 #if GLIB_CHECK_VERSION (2,31,0) 966 g_mutex_lock (&priv->initialization_mutex); 967 while (!priv->initialized) 968 g_cond_wait (&priv->initialization_cond, &priv->initialization_mutex); 969 g_mutex_unlock (&priv->initialization_mutex); 970 #else 971 g_mutex_lock (priv->initialization_mutex); 972 while (!priv->initialized) 973 g_cond_wait (priv->initialization_cond, priv->initialization_mutex); 974 g_mutex_unlock (priv->initialization_mutex); 975 #endif 976 977 /* If there was any error resulting from initialization, propagate it */ 978 if (priv->initialization_error != NULL) { 979 g_propagate_error (error, priv->initialization_error); 980 return FALSE; 981 } 982 983 #ifdef THREAD_ENABLE_TRACE 984 g_debug ("Thread:%p (Controller) --- Initialized", 985 g_thread_self ()); 986 #endif /* THREAD_ENABLE_TRACE */ 987 988 return TRUE; 989 }