1 /* vi:set et ai sw=2 sts=2 ts=2: */
3 * Copyright (c) 2012 GENIVI.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 #include <glib-object.h>
17 #include <node-startup-controller/job-manager.h>
18 #include <node-startup-controller/systemd-manager-dbus.h>
22 typedef struct _JobManagerJob JobManagerJob;
26 /* property identifiers */
36 static void job_manager_constructed (GObject *object);
37 static void job_manager_finalize (GObject *object);
38 static void job_manager_get_property (GObject *object,
42 static void job_manager_set_property (GObject *object,
46 static void job_manager_start_unit_reply (GObject *object,
49 static void job_manager_stop_unit_reply (GObject *object,
52 static void job_manager_job_removed (SystemdManager *systemd_manager,
54 const gchar *job_name,
57 JobManager *job_manager);
58 static JobManagerJob *job_manager_job_new (JobManager *manager,
60 GCancellable *cancellable,
61 JobManagerCallback callback,
63 static void job_manager_job_unref (JobManagerJob *job);
64 static void job_manager_remember_job (JobManager *manager,
65 const gchar *job_name,
67 static void job_manager_forget_job (JobManager *manager,
68 const gchar *job_name);
72 struct _JobManagerClass
74 GObjectClass __parent__;
81 GDBusConnection *connection;
82 SystemdManager *systemd_manager;
91 GCancellable *cancellable;
92 JobManagerCallback callback;
98 G_DEFINE_TYPE (JobManager, job_manager, G_TYPE_OBJECT);
103 job_manager_class_init (JobManagerClass *klass)
105 GObjectClass *gobject_class;
107 gobject_class = G_OBJECT_CLASS (klass);
108 gobject_class->finalize = job_manager_finalize;
109 gobject_class->constructed = job_manager_constructed;
110 gobject_class->get_property = job_manager_get_property;
111 gobject_class->set_property = job_manager_set_property;
113 g_object_class_install_property (gobject_class,
115 g_param_spec_object ("connection",
118 G_TYPE_DBUS_CONNECTION,
120 G_PARAM_CONSTRUCT_ONLY |
121 G_PARAM_STATIC_STRINGS));
123 g_object_class_install_property (gobject_class,
124 PROP_SYSTEMD_MANAGER,
125 g_param_spec_object ("systemd-manager",
128 TYPE_SYSTEMD_MANAGER,
130 G_PARAM_CONSTRUCT_ONLY |
131 G_PARAM_STATIC_STRINGS));
137 job_manager_init (JobManager *manager)
139 /* create a mapping of systemd job names to job objects; we will use this
140 * to remember jobs that we started */
141 manager->jobs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
142 (GDestroyNotify) job_manager_job_unref);
149 job_manager_finalize (GObject *object)
151 JobManager *manager = JOB_MANAGER (object);
153 /* release all the jobs we have remembered */
154 g_hash_table_unref (manager->jobs);
156 /* release the D-Bus connection */
157 g_object_unref (manager->connection);
159 /* release the systemd manager */
160 g_signal_handlers_disconnect_matched (manager->systemd_manager,
162 0, 0, NULL, NULL, manager);
163 g_object_unref (manager->systemd_manager);
165 /* chain up to finalize parent class */
166 (*G_OBJECT_CLASS (job_manager_parent_class)->finalize) (object);
172 job_manager_constructed (GObject *object)
174 JobManager *manager = JOB_MANAGER (object);
176 /* connect to systemd's "JobRemoved" signal so that we are notified
177 * whenever a job is finished */
178 g_signal_connect (manager->systemd_manager, "job-removed",
179 G_CALLBACK (job_manager_job_removed), manager);
185 job_manager_get_property (GObject *object,
190 JobManager *manager = JOB_MANAGER (object);
194 case PROP_CONNECTION:
195 g_value_set_object (value, manager->connection);
197 case PROP_SYSTEMD_MANAGER:
198 g_value_set_object (value, manager->systemd_manager);
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
209 job_manager_set_property (GObject *object,
214 JobManager *manager = JOB_MANAGER (object);
218 case PROP_CONNECTION:
219 manager->connection = g_value_dup_object (value);
221 case PROP_SYSTEMD_MANAGER:
222 manager->systemd_manager = g_value_dup_object (value);
225 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
233 job_manager_start_unit_reply (GObject *object,
234 GAsyncResult *result,
237 JobManagerJob *job = user_data;
238 GError *error = NULL;
239 gchar *job_name = NULL;
241 g_return_if_fail (IS_SYSTEMD_MANAGER (object));
242 g_return_if_fail (G_IS_ASYNC_RESULT (result));
243 g_return_if_fail (user_data != NULL);
245 /* finish the start unit call */
246 if (!systemd_manager_call_start_unit_finish (job->manager->systemd_manager,
247 &job_name, result, &error))
249 /* there was an error. notify the caller */
250 job->callback (job->manager, job->unit, "failed", error, job->user_data);
251 g_error_free (error);
254 /* finish the job immediately */
255 job_manager_job_unref (job);
259 /* remember the job so that we can finish it in the "job-removed" signal handler.
260 * the service takes ownership of the job so we don't need to unref it here */
261 job_manager_remember_job (job->manager, job_name, job);
268 job_manager_stop_unit_reply (GObject *object,
269 GAsyncResult *result,
272 JobManagerJob *job = user_data;
273 GError *error = NULL;
274 gchar *job_name = NULL;
276 g_return_if_fail (IS_SYSTEMD_MANAGER (object));
277 g_return_if_fail (G_IS_ASYNC_RESULT (result));
278 g_return_if_fail (user_data != NULL);
280 /* finish the stop unit call */
281 if (!systemd_manager_call_stop_unit_finish (job->manager->systemd_manager,
282 &job_name, result, &error))
284 /* there was an error. notify the caller */
285 job->callback (job->manager, job->unit, "failed", error, job->user_data);
286 g_error_free (error);
289 /* finish the job immediately */
290 job_manager_job_unref (job);
294 /* remember the job so that we can finish it in the "job-removed" signal handler.
295 * the service takes ownership of the job so we don't need to unref it here */
296 job_manager_remember_job (job->manager, job_name, job);
303 job_manager_job_removed (SystemdManager *systemd_manager,
305 const gchar *job_name,
308 JobManager *job_manager)
312 g_return_if_fail (IS_SYSTEMD_MANAGER (systemd_manager));
313 g_return_if_fail (job_name != NULL && *job_name != '\0');
314 g_return_if_fail (result != NULL && *result != '\0');
315 g_return_if_fail (unit != NULL && *unit != '\0');
316 g_return_if_fail (IS_JOB_MANAGER (job_manager));
318 /* look up the remembered job for this job name */
319 job = g_hash_table_lookup (job_manager->jobs, job_name);
321 /* if no job is found, ignore this job-removed signal */
325 /* finish the job by notifying the caller */
326 job->callback (job_manager, job->unit, result, NULL, job->user_data);
328 /* forget about this job */
329 job_manager_forget_job (job_manager, job_name);
334 static JobManagerJob *
335 job_manager_job_new (JobManager *manager,
337 GCancellable *cancellable,
338 JobManagerCallback callback,
343 g_return_val_if_fail (IS_JOB_MANAGER (manager), NULL);
344 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
346 /* allocate a new job struct */
347 job = g_slice_new0 (JobManagerJob);
348 job->manager = g_object_ref (manager);
349 job->unit = g_strdup(unit);
350 if (cancellable != NULL)
351 job->cancellable = g_object_ref (cancellable);
352 job->callback = callback;
353 job->user_data = user_data;
360 job_manager_job_unref (JobManagerJob *job)
365 /* release all memory and references held by job */
366 if (job->cancellable != NULL)
367 g_object_unref (job->cancellable);
369 g_object_unref (job->manager);
370 g_slice_free (JobManagerJob, job);
376 job_manager_remember_job (JobManager *manager,
377 const char *job_name,
380 JobManagerJob *existing_job;
382 g_return_if_fail (IS_JOB_MANAGER (manager));
383 g_return_if_fail (job_name != NULL && *job_name != '\0');
384 g_return_if_fail (job != NULL);
386 /* if the job is already being remembered, there is a programming error that should be
388 existing_job = g_hash_table_lookup (manager->jobs, job_name);
389 if (existing_job != NULL)
391 g_critical ("Trying to remember the same job twice.");
394 /* associate the job name with the job */
395 g_hash_table_insert (manager->jobs, g_strdup (job_name), job);
401 job_manager_forget_job (JobManager *manager,
402 const gchar *job_name)
404 g_return_if_fail (IS_JOB_MANAGER (manager));
405 g_return_if_fail (job_name != NULL && *job_name != '\0');
407 g_hash_table_remove (manager->jobs, job_name);
413 job_manager_new (GDBusConnection *connection,
414 SystemdManager *systemd_manager)
416 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
417 g_return_val_if_fail (IS_SYSTEMD_MANAGER (systemd_manager), NULL);
419 return g_object_new (TYPE_JOB_MANAGER,
420 "connection", connection,
421 "systemd-manager", systemd_manager,
428 job_manager_start (JobManager *manager,
430 GCancellable *cancellable,
431 JobManagerCallback callback,
436 g_return_if_fail (IS_JOB_MANAGER (manager));
437 g_return_if_fail (unit != NULL);
438 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
439 g_return_if_fail (callback != NULL);
441 /* create a new job object */
442 job = job_manager_job_new (manager, unit, cancellable, callback, user_data);
444 /* ask systemd to start the unit asynchronously */
445 systemd_manager_call_start_unit (manager->systemd_manager, unit, "fail", cancellable,
446 job_manager_start_unit_reply, job);
452 job_manager_stop (JobManager *manager,
454 GCancellable *cancellable,
455 JobManagerCallback callback,
460 g_return_if_fail (IS_JOB_MANAGER (manager));
461 g_return_if_fail (unit != NULL);
462 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
463 g_return_if_fail (callback != NULL);
465 /* create a new job object */
466 job = job_manager_job_new (manager, unit, cancellable, callback, user_data);
468 /* ask systemd to stop the unit asynchronously */
469 systemd_manager_call_stop_unit (manager->systemd_manager, unit, "fail", cancellable,
470 job_manager_stop_unit_reply, job);