source: mainline/uspace/srv/sysman/sysman.c@ c0e4fc50

Last change on this file since c0e4fc50 was 5559712, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

sysman: Naive autostart instrumentation of locsrv

  • Add IPC_FLAG_AUTOSTART flag.
  • libsysman: sysman's broker and control API.
  • Simple implementation of service unit, exposee verification is missing.
  • Simple mapping of exposee to unit name in locsrv.
  • Temporary debug prints in locsrv.

Conflicts:

boot/Makefile.common
boot/arch/amd64/Makefile.inc
uspace/lib/c/include/ipc/services.h
uspace/srv/locsrv/locsrv.c

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2015 Michal Koutny
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <adt/hash_table.h>
30#include <adt/list.h>
31#include <errno.h>
32#include <fibril_synch.h>
33#include <stdlib.h>
34
35#include "log.h"
36#include "sysman.h"
37#include "unit.h"
38
39
40/* Do not expose this generally named type */
41typedef struct {
42 link_t event_queue;
43
44 event_handler_t handler;
45 void *data;
46} event_t;
47
48typedef struct {
49 link_t callbacks;
50
51 callback_handler_t handler;
52 void *data;
53} obj_callback_t;
54
55typedef struct {
56 ht_link_t ht_link;
57
58 void *object;
59 list_t callbacks;
60} observed_object_t;
61
62static LIST_INITIALIZE(event_queue);
63static fibril_mutex_t event_queue_mtx;
64static fibril_condvar_t event_queue_cv;
65
66static hash_table_t observed_objects;
67static fibril_mutex_t observed_objects_mtx;
68static fibril_condvar_t observed_objects_cv;
69
70/* Hash table functions */
71static size_t observed_objects_ht_hash(const ht_link_t *item)
72{
73 observed_object_t *callbacks =
74 hash_table_get_inst(item, observed_object_t, ht_link);
75
76 return (size_t) callbacks->object;
77}
78
79static size_t observed_objects_ht_key_hash(void *key)
80{
81 void *object = *(void **) key;
82 return (size_t) object;
83}
84
85static bool observed_objects_ht_key_equal(void *key, const ht_link_t *item)
86{
87 void *object = *(void **)key;
88 return (
89 hash_table_get_inst(item, observed_object_t, ht_link)->object ==
90 object);
91}
92
93static hash_table_ops_t observed_objects_ht_ops = {
94 .hash = &observed_objects_ht_hash,
95 .key_hash = &observed_objects_ht_key_hash,
96 .equal = NULL,
97 .key_equal = &observed_objects_ht_key_equal,
98 .remove_callback = NULL
99};
100
101static void notify_observers(void *object)
102{
103 ht_link_t *item = hash_table_find(&observed_objects, &object);
104 if (item == NULL) {
105 return;
106 }
107 observed_object_t *observed_object =
108 hash_table_get_inst(item, observed_object_t, ht_link);
109
110 list_foreach_safe(observed_object->callbacks, cur_link, next_link) {
111 obj_callback_t *callback =
112 list_get_instance(cur_link, obj_callback_t, callbacks);
113 callback->handler(object, callback->data);
114 list_remove(cur_link);
115 free(callback);
116 }
117}
118
119/*
120 * Non-static functions
121 */
122void sysman_events_init(void)
123{
124 fibril_mutex_initialize(&event_queue_mtx);
125 fibril_condvar_initialize(&event_queue_cv);
126
127 bool table =
128 hash_table_create(&observed_objects, 0, 0, &observed_objects_ht_ops);
129 if (!table) {
130 sysman_log(LVL_FATAL, "%s: Failed initialization", __func__);
131 abort();
132 }
133 fibril_mutex_initialize(&observed_objects_mtx);
134 fibril_condvar_initialize(&observed_objects_cv);
135}
136
137int sysman_events_loop(void *unused)
138{
139 while (1) {
140 /* Pop event */
141 fibril_mutex_lock(&event_queue_mtx);
142 while (list_empty(&event_queue)) {
143 fibril_condvar_wait(&event_queue_cv, &event_queue_mtx);
144 }
145
146 link_t *li_event = list_first(&event_queue);
147 list_remove(li_event);
148 event_t *event =
149 list_get_instance(li_event, event_t, event_queue);
150 fibril_mutex_unlock(&event_queue_mtx);
151
152 /* Process event */
153 sysman_log(LVL_DEBUG2, "process_event(%p, %p)",
154 event->handler, event->data);
155 event->handler(event->data);
156 free(event);
157 }
158}
159
160/** Create and queue job for unit
161 *
162 * @param[in] callback callback must explicitly delete reference to job
163 */
164int sysman_queue_job(unit_t *unit, unit_state_t target_state,
165 callback_handler_t callback, void *callback_arg)
166{
167 job_t *job = job_create(unit, target_state);
168 if (job == NULL) {
169 return ENOMEM;
170 }
171
172 job_add_ref(job);
173 sysman_object_observer(job, callback, callback_arg);
174
175 job_add_ref(job);
176 sysman_raise_event(&sysman_event_job_process, job);
177
178 job_del_ref(&job);
179 return EOK;
180}
181
182void sysman_raise_event(event_handler_t handler, void *data)
183{
184 sysman_log(LVL_DEBUG2, "%s(%p, %p)", __func__, handler, data);
185 event_t *event = malloc(sizeof(event_t));
186 if (event == NULL) {
187 sysman_log(LVL_FATAL, "%s: cannot allocate event", __func__);
188 // TODO think about aborting system critical task
189 abort();
190 }
191 link_initialize(&event->event_queue);
192 event->handler = handler;
193 event->data = data;
194
195 fibril_mutex_lock(&event_queue_mtx);
196 list_append(&event->event_queue, &event_queue);
197 /* There's only single event loop, broadcast is unnecessary */
198 fibril_condvar_signal(&event_queue_cv);
199 fibril_mutex_unlock(&event_queue_mtx);
200}
201
202/** Register single-use object observer callback
203 *
204 * TODO no one handles return value, it's quite fatal to lack memory for
205 * callbacks... @return EOK on success
206 * @return ENOMEM
207 */
208int sysman_object_observer(void *object, callback_handler_t handler, void *data)
209{
210 int rc;
211 observed_object_t *observed_object = NULL;
212 observed_object_t *new_observed_object = NULL;
213 ht_link_t *ht_link = hash_table_find(&observed_objects, &object);
214
215 if (ht_link == NULL) {
216 observed_object = malloc(sizeof(observed_object_t));
217 if (observed_object == NULL) {
218 rc = ENOMEM;
219 goto fail;
220 }
221 new_observed_object = observed_object;
222
223 observed_object->object = object;
224 list_initialize(&observed_object->callbacks);
225 hash_table_insert(&observed_objects, &observed_object->ht_link);
226 } else {
227 observed_object =
228 hash_table_get_inst(ht_link, observed_object_t, ht_link);
229 }
230
231 obj_callback_t *obj_callback = malloc(sizeof(obj_callback_t));
232 if (obj_callback == NULL) {
233 rc = ENOMEM;
234 goto fail;
235 }
236
237 obj_callback->handler = handler;
238 obj_callback->data = data;
239 list_append(&obj_callback->callbacks, &observed_object->callbacks);
240 return EOK;
241
242fail:
243 free(new_observed_object);
244 return rc;
245}
246
247/*
248 * Event handlers
249 */
250
251// NOTE must run in main event loop fibril
252void sysman_event_job_process(void *data)
253{
254 job_t *job = data;
255 dyn_array_t job_closure;
256 dyn_array_initialize(&job_closure, job_ptr_t, 0);
257
258 int rc = job_create_closure(job, &job_closure);
259 if (rc != EOK) {
260 sysman_log(LVL_ERROR, "Cannot create closure for job %p (%i)",
261 job, rc);
262 goto fail;
263 }
264
265 /*
266 * If jobs are queued, reference is passed from closure to the queue,
267 * otherwise, we still have the reference.
268 */
269 rc = job_queue_add_jobs(&job_closure);
270 if (rc != EOK) {
271 goto fail;
272 }
273 /* We don't need job anymore */
274 job_del_ref(&job);
275
276 job_queue_process();
277 return;
278
279fail:
280 job->retval = JOB_FAILED;
281 job_finish(job);
282 job_del_ref(&job);
283
284 dyn_array_foreach(job_closure, job_ptr_t, closure_job) {
285 job_del_ref(&(*closure_job));
286 }
287 dyn_array_destroy(&job_closure);
288}
289
290void sysman_event_job_finished(void *data)
291{
292 notify_observers(data);
293 /* Unreference the event data */
294 job_t *job = data;
295 job_del_ref(&job);
296
297 /* The finished job, might have been blocking */
298 job_queue_process();
299}
300
301void sysman_event_unit_exposee_created(void *data)
302{
303 unit_t *unit = data;
304 unit_exposee_created(unit);
305}
306
307void sysman_event_unit_failed(void *data)
308{
309 unit_t *unit = data;
310 unit_fail(unit);
311}
312
313void sysman_event_unit_state_changed(void *data)
314{
315 notify_observers(data);
316}
Note: See TracBrowser for help on using the repository browser.