2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <murphy/common/debug.h>
33 #include <murphy/common/mm.h>
34 #include <murphy/common/list.h>
35 #include <murphy/common/msg.h>
37 #include <murphy/core/event.h>
45 char *name; /* event name */
46 int id; /* associated event id */
47 mrp_list_hook_t watches; /* single-event watches */
55 struct mrp_event_watch_s {
56 mrp_list_hook_t hook; /* hook to event watch list */
57 mrp_list_hook_t purge; /* hook to deleted event list */
58 mrp_event_cb_t cb; /* notification callback */
59 mrp_event_mask_t events; /* events to watch */
60 void *user_data; /* opaque callback data */
64 static event_def_t events[MRP_EVENT_MAX]; /* event table */
65 static int nevent; /* number of events */
66 static int nemit; /* events being emitted */
67 static mrp_list_hook_t watches; /* multi-event watches */
68 static mrp_list_hook_t deleted; /* events deleted during emit */
71 static int single_event(mrp_event_mask_t *mask);
74 MRP_INIT static void init_watch_lists(void)
78 for (i = 0; i < MRP_EVENT_MAX; i++)
79 mrp_list_init(&events[i].watches);
81 mrp_list_init(&watches);
82 mrp_list_init(&deleted);
86 mrp_event_watch_t *mrp_add_event_watch(mrp_event_mask_t *mask,
87 mrp_event_cb_t cb, void *user_data)
94 w = mrp_allocz(sizeof(*w));
97 mrp_list_init(&w->hook);
98 mrp_list_init(&w->purge);
100 w->user_data = user_data;
103 id = single_event(mask);
105 if (id != MRP_EVENT_UNKNOWN) {
106 if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
109 if (def->name != NULL)
110 mrp_list_append(&def->watches, &w->hook);
122 mrp_list_append(&watches, &w->hook);
131 if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
134 if (def->name != NULL && cb != NULL) {
135 w = mrp_allocz(sizeof(*w));
138 mrp_list_init(&w->hook);
139 mrp_list_init(&w->purge);
141 w->user_data = user_data;
143 if (single_event(mask)) {
144 id = single_event(mask);
146 mrp_list_append(&def->watches, &w->hook);
158 static void delete_watch(mrp_event_watch_t *w)
160 mrp_list_delete(&w->hook);
161 mrp_list_delete(&w->purge);
166 static void purge_deleted(void)
168 mrp_event_watch_t *w;
169 mrp_list_hook_t *p, *n;
171 mrp_list_foreach(&deleted, p, n) {
172 w = mrp_list_entry(p, typeof(*w), purge);
178 void mrp_del_event_watch(mrp_event_watch_t *w)
182 mrp_list_append(&deleted, &w->purge);
189 int mrp_get_event_id(const char *name, int create)
194 for (i = MRP_EVENT_UNKNOWN + 1, def = events + i; i <= nevent; i++, def++) {
195 if (!strcmp(name, def->name))
200 if (nevent < MRP_EVENT_MAX - 1) {
201 def = events + 1 + nevent;
202 def->name = mrp_strdup(name);
204 if (def->name != NULL) {
205 mrp_list_init(&def->watches);
206 def->id = 1 + nevent++;
213 return MRP_EVENT_UNKNOWN;
217 const char *mrp_get_event_name(int id)
221 if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
227 return "<unknown event>";
231 int mrp_emit_event_msg(int id, mrp_msg_t *event_data)
234 mrp_list_hook_t *p, *n;
235 mrp_event_watch_t *w;
237 if (MRP_EVENT_UNKNOWN < id && id <= nevent) {
240 if (def->name != NULL) {
242 mrp_msg_ref(event_data);
244 mrp_debug("emitting event 0x%x (%s)", def->id, def->name);
246 mrp_msg_dump(event_data, stdout);
249 mrp_list_foreach(&def->watches, p, n) {
250 w = mrp_list_entry(p, typeof(*w), hook);
251 w->cb(w, def->id, event_data, w->user_data);
254 mrp_list_foreach(&watches, p, n) {
255 w = mrp_list_entry(p, typeof(*w), hook);
256 if (mrp_test_event(&w->events, id))
257 w->cb(w, def->id, event_data, w->user_data);
261 mrp_msg_unref(event_data);
274 int mrp_emit_event(int id, ...)
282 tag = va_arg(ap, unsigned int);
283 if (tag != MRP_MSG_FIELD_INVALID)
284 msg = mrp_msg_createv(tag, ap);
289 success = mrp_emit_event_msg(id, msg);
296 mrp_event_mask_t *mrp_set_events(mrp_event_mask_t *mask, ...)
301 mrp_reset_event_mask(mask);
304 while ((id = va_arg(ap, int)) != MRP_EVENT_UNKNOWN) {
305 mrp_add_event(mask, id);
313 mrp_event_mask_t *mrp_set_named_events(mrp_event_mask_t *mask, ...)
319 mrp_reset_event_mask(mask);
322 while ((name = va_arg(ap, const char *)) != NULL) {
323 id = mrp_lookup_event(name);
325 if (id != MRP_EVENT_UNKNOWN)
326 mrp_add_event(mask, id);
334 static int event_count(mrp_event_mask_t *mask)
336 uint64_t bits = *mask;
338 return __builtin_popcountll(bits);
342 static int lowest_bit(mrp_event_mask_t *mask)
344 uint64_t bits = *mask;
346 return __builtin_ffs(bits);
350 static int single_event(mrp_event_mask_t *mask)
352 if (event_count(mask) == 1)
353 return lowest_bit(mask);
355 return MRP_EVENT_UNKNOWN;