source: roaraudio/libroar/notify.c @ 5373:8da157c10483

Last change on this file since 5373:8da157c10483 was 5311:778a3e7b2b66, checked in by phi, 12 years ago

added roar_notify_core_swap_global() wich can be used to create diffrent global contextes

File size: 13.3 KB
Line 
1//notify.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38struct roar_subscriber {
39 uint32_t flags;
40 uint32_t event;
41 int emitter;
42 int target;
43 int target_type;
44 void (*cb)(struct roar_notify_core * core, struct roar_event * event, void * userdata);
45 void * userdata;
46 size_t refc;
47 unsigned int hash;
48// struct roar_subscriber * prev;
49 struct roar_subscriber * next;
50};
51
52struct roar_notify_core {
53 size_t refc;
54 size_t listc;
55 struct roar_subscriber ** lists;
56 void (*proxy)(struct roar_notify_core * core, struct roar_event * event, void * userdata);
57 void * proxy_userdata;
58};
59
60static struct roar_notify_core * _libroar_notify_core = NULL;
61
62#define _CKRCORE(ret) if ( core == NULL ) { if ( _libroar_notify_core == NULL ) { roar_err_set(ROAR_ERROR_INVAL); return (ret); } else { core = _libroar_notify_core; } }
63#define _CKICORE() _CKRCORE(-1)
64
65static unsigned int _hash_event (struct roar_notify_core * core, struct roar_event * event) {
66 unsigned int hash = 0;
67 unsigned int mask = core->listc - 1;
68
69 hash ^= event->event >>  0;
70 hash ^= event->event >>  8;
71 hash ^= event->event >> 16;
72 hash ^= event->event >> 24;
73
74 return hash & mask;
75}
76
77struct roar_notify_core * roar_notify_core_new(ssize_t lists) {
78 struct roar_notify_core * core = NULL;
79
80 switch (lists) {
81  case    1:
82  case    2:
83  case    4:
84  case    8:
85  case   16:
86  case   32:
87  case   64:
88  case  128:
89  case  256:
90  case  512:
91  case 1024:
92    // they all are ok.
93   break;
94  case  -1:
95    // handle defult:
96    lists = 16;
97   break;
98  default:
99    roar_err_set(ROAR_ERROR_INVAL);
100    return NULL;
101   break;
102 }
103
104 if ( (core = roar_mm_malloc(sizeof(struct roar_notify_core))) == NULL ) {
105  return NULL;
106 }
107
108 memset(core, 0, sizeof(struct roar_notify_core));
109
110 core->refc  = 1;
111 core->listc = lists;
112 core->lists = roar_mm_malloc(lists*sizeof(struct roar_subscriber *));
113 core->proxy = NULL;
114 core->proxy_userdata = NULL;
115
116 if ( core->lists == NULL ) {
117  roar_mm_free(core);
118  return NULL;
119 }
120
121 memset(core->lists, 0, lists*sizeof(struct roar_subscriber *));
122
123 return core;
124}
125
126int roar_notify_core_ref(struct roar_notify_core * core) {
127 _CKICORE();
128
129 core->refc++;
130
131 return 0;
132}
133
134int roar_notify_core_unref(struct roar_notify_core * core) {
135 struct roar_subscriber * cur, * next;
136 size_t i;
137
138 _CKICORE();
139
140 if ( core->refc == 0 ) {
141  ROAR_ERR("roar_notify_core_unref(core=%p): refc is zero, must be greater zero. resolving by setting to one.", core);
142  core->refc = 1;
143  roar_panic(ROAR_FATAL_ERROR_MEMORY_CORRUPTION, NULL);
144 }
145
146 core->refc--;
147
148 if ( core->refc > 0 ) {
149  return 0;
150 }
151
152 // if we work on the global core, reset it to NULL if we free it.
153 if ( core == _libroar_notify_core ) {
154  _libroar_notify_core = NULL;
155 }
156
157 for (i = 0; i < core->listc; i++) {
158  cur = core->lists[i];
159  while (cur != NULL) {
160   next = cur->next;
161
162   roar_mm_free(cur);
163
164   cur = next;
165  }
166 }
167
168 roar_mm_free(core->lists);
169 roar_mm_free(core);
170 return 0;
171}
172
173int roar_notify_core_new_global(ssize_t lists) {
174 if ( _libroar_notify_core != NULL ) {
175  roar_err_set(ROAR_ERROR_INVAL);
176  return -1;
177 }
178
179 if ( (_libroar_notify_core = roar_notify_core_new(lists)) == NULL )
180  return -1;
181
182 return 0;
183}
184
185struct roar_notify_core * roar_notify_core_swap_global(struct roar_notify_core * core) {
186 struct roar_notify_core * ret = _libroar_notify_core;
187
188 if ( core != NULL )
189  if ( roar_notify_core_ref(core) == -1 )
190   return NULL;
191
192 _libroar_notify_core = core;
193
194 return ret;
195}
196
197int roar_notify_core_register_proxy(struct roar_notify_core * core, void (*cb)(struct roar_notify_core * core, struct roar_event * event, void * userdata), void * userdata) {
198 _CKICORE();
199
200 core->proxy = cb;
201 core->proxy_userdata = userdata;
202
203 return 0;
204}
205
206
207struct roar_subscriber * roar_notify_core_subscribe(struct roar_notify_core * core, struct roar_event * event, void (*cb)(struct roar_notify_core * core, struct roar_event * event, void * userdata), void * userdata) {
208 struct roar_subscriber * subs = NULL;
209 struct roar_subscriber * cur, * old;
210
211 ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = ?", core, event, cb, userdata);
212
213 _CKRCORE(NULL);
214
215 if ( event == NULL || cb == NULL ) {
216  ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = NULL // errno = EINVAL", core, event, cb, userdata);
217  roar_err_set(ROAR_ERROR_FAULT);
218  return NULL;
219 }
220
221 if ( (subs = roar_mm_malloc(sizeof(struct roar_subscriber))) == NULL ) {
222  ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = NULL // errno = ENOMEM?", core, event, cb, userdata);
223  return NULL;
224 }
225
226 memset(subs, 0, sizeof(struct roar_subscriber));
227
228 subs->flags       = 0;
229 subs->event       = event->event;
230 subs->emitter     = event->emitter;
231 subs->target      = event->target;
232 subs->target_type = event->target_type;
233 subs->cb          = cb;
234 subs->userdata    = userdata;
235 subs->refc        = 1;
236 subs->hash        = _hash_event(core, event);
237 subs->next        = NULL;
238
239 if ( (cur = core->lists[subs->hash]) == NULL ) {
240  core->lists[subs->hash] = subs;
241 } else {
242  old = cur;
243  while (cur != NULL) {
244   old = cur;
245   cur = cur->next;
246  }
247
248  old->next = subs;
249 }
250
251 ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = %p", core, event, cb, userdata, subs);
252 return subs;
253}
254
255int roar_notify_core_unsubscribe(struct roar_notify_core * core, struct roar_subscriber * subscriber) {
256 struct roar_subscriber * cur, * old;
257
258 _CKICORE();
259
260 if ( subscriber == NULL ) {
261  roar_err_set(ROAR_ERROR_FAULT);
262  return -1;
263 }
264
265 if ( (cur = core->lists[subscriber->hash]) == subscriber ) {
266  core->lists[subscriber->hash] = core->lists[subscriber->hash]->next;
267 } else {
268  old = NULL;
269  while (cur != NULL && cur != subscriber ) {
270   old = cur;
271   cur = cur->next;
272  }
273
274  if ( cur != subscriber )
275   return -1;
276
277  old->next = cur->next;
278  roar_mm_free(cur);
279 }
280
281 return 0;
282}
283
284int roar_notify_core_emit(struct roar_notify_core * core, struct roar_event * event) {
285 struct roar_subscriber * cur;
286 struct roar_error_state errstate;
287
288 _CKICORE();
289
290 if ( event == NULL ) {
291  roar_err_set(ROAR_ERROR_FAULT);
292  return -1;
293 }
294
295 if ( core->proxy != NULL && !(event->flags & ROAR_EVENT_FLAG_PROXYEVENT) ) {
296  core->proxy(core, event, core->proxy_userdata);
297 }
298
299 cur = core->lists[_hash_event(core, event)];
300 ROAR_DBG("roar_notify_core_emit(core=%p, event=%p): cur=%p", core, event, cur);
301
302 while (cur != NULL) {
303  ROAR_DBG("roar_notify_core_emit(core=%p, event=%p): cur=%p", core, event, cur);
304
305  // test if we can skip this one:
306  if ( !( (cur->event       == ROAR_NOTIFY_SPECIAL || cur->event       == event->event)   &&
307          (cur->emitter     == -1                  || cur->emitter     == event->emitter) &&
308          (cur->target      == -1                  || cur->target      == event->target)  &&
309          (cur->target_type == -1                  || cur->target_type == event->target_type)
310        ) ) {
311   cur = cur->next;
312   continue;
313  }
314
315  if ( cur->cb == NULL ) {
316   ROAR_ERR("roar_notify_core_emit(core=%p, event=%p): cur=%p, cb is set NULL, bad.", core, event, cur);
317  } else {
318   // The callback is started in an clear error context which is destroyed after it finished so it
319   // does not alter our caller's context.
320   roar_err_store(&errstate);
321   roar_err_clear_all();
322
323   cur->cb(core, event, cur->userdata);
324
325   roar_err_restore(&errstate);
326  }
327  cur = cur->next;
328 }
329
330 return 0;
331}
332
333int roar_notify_core_emit_simple(uint32_t event, int emitter, int target, int target_type, int arg0, int arg1, void * arg2, ssize_t arg2_len) {
334 struct roar_event locevent;
335
336 memset(&locevent, 0, sizeof(locevent));
337
338 locevent.event = event;
339 locevent.emitter = emitter;
340 locevent.target = target;
341 locevent.target_type = target_type;
342 locevent.arg0 = arg0;
343 locevent.arg1 = arg1;
344 locevent.arg2 = arg2;
345 locevent.arg2_len = arg2_len;
346
347 if ( arg2 == NULL && (arg2_len == 0 || arg2_len == -1) ) {
348  locevent.flags |= ROAR_EVENT_FLAG_NETTRANS; // we guss packages with only int args are network transparent.
349 }
350
351 return roar_notify_core_emit(NULL, &locevent);
352}
353
354
355int roar_event_to_blob(struct roar_event * event, void * blob, size_t * len) {
356 size_t needed_len = (2 * 4) + (4 * 2);
357 uint32_t * u32 = blob;
358 uint16_t * u16 = blob;
359 size_t data_offset_neg = 0;
360
361 u16 += 4;
362
363 // error checking:
364 if ( event == NULL || blob == NULL || len == NULL )
365  return -1;
366
367 if ( *len == 0 )
368  return -1;
369
370 // calc and check length:
371 if ( event->flags & ROAR_EVENT_FLAG_PROXYEVENT )
372  needed_len += 4;
373
374 if ( event->flags & ROAR_EVENT_FLAG_NETTRANS ) {
375
376  // this is not a real maximum but a value good to detect all kinds of errors.
377  // a notify event should not be longer anyway.
378  if ( event->arg2_len > 32767 )
379   return -1;
380
381  needed_len += 4;
382  if ( event->arg2_len > 0 ) {
383    needed_len += event->arg2_len;
384    data_offset_neg = event->arg2_len;
385  }
386 }
387
388 if ( *len < needed_len )
389  return -1;
390
391 *len = 0;
392
393 // fill in the data...
394 memset(blob, 0, needed_len);
395
396 u32[1] = ROAR_HOST2NET32(0);
397
398 if ( event->flags & ROAR_EVENT_FLAG_PROXYEVENT ) {
399  u32[0] |= ROAR_HOST2NET32(ROAR_EVENT_NETFLAG_PROXYEVENT);
400  u16 += 2;
401 }
402
403 if ( event->flags & ROAR_EVENT_FLAG_NETTRANS ) {
404  u32[0] |= ROAR_HOST2NET32(ROAR_EVENT_NETFLAG_DATA);
405 }
406
407 u32[1] = ROAR_HOST2NET32(event->event);
408
409 if ( event->flags & ROAR_EVENT_FLAG_PROXYEVENT )
410  u32[2] = ROAR_HOST2NET32(event->event_proxy);
411
412 u16[0] = ROAR_HOST2NET16(event->emitter);
413 u16[1] = ROAR_HOST2NET16(event->target);
414 u16[2] = ROAR_HOST2NET16(event->target_type);
415 if ( event->flags & ROAR_EVENT_FLAG_NETTRANS ) {
416  u16[3] = ROAR_HOST2NET16(event->arg2_len);
417  u16[4] = ROAR_HOST2NET16(event->arg0);
418  u16[5] = ROAR_HOST2NET16(event->arg1);
419 } else {
420  u16[3] = ROAR_HOST2NET16(0);
421 }
422
423 memcpy(blob + needed_len - data_offset_neg, event->arg2, event->arg2_len);
424
425 *len = needed_len;
426
427 return 0;
428}
429
430int roar_event_from_blob(struct roar_event * event, void * blob, size_t * len) {
431 size_t needed_len = (2 * 4) + (4 * 2);
432 uint32_t * u32 = blob;
433 uint16_t * u16 = blob;
434 uint32_t flags;
435
436 u16 += 4;
437
438 // error checking:
439 if ( event == NULL || blob == NULL || len == NULL )
440  return -1;
441
442 // check for minimum length.
443 if ( *len < needed_len )
444  return -1;
445
446 flags = ROAR_NET2HOST32(u32[0]);
447
448#if 0
449 if ( event->flags & ROAR_EVENT_FLAG_PROXYEVENT ) {
450  u32[0] |= ROAR_HOST2NET32(ROAR_EVENT_NETFLAG_PROXYEVENT);
451  u16 += 2;
452 }
453
454 if ( event->flags & ROAR_EVENT_FLAG_NETTRANS ) {
455  u32[0] |= ROAR_HOST2NET32(ROAR_EVENT_NETFLAG_DATA);
456 }
457#endif
458
459 if ( flags & ROAR_EVENT_NETFLAG_PROXYEVENT ) {
460  needed_len += 4;
461  u16 += 2;
462 }
463
464 if ( flags & ROAR_EVENT_NETFLAG_DATA ) {
465  needed_len += 4;
466 }
467
468 // do we have a full header?
469 if ( *len < needed_len )
470  return -1;
471
472 needed_len += ROAR_NET2HOST16(u16[3]);
473
474 // is all of the event complet?
475 if ( *len < needed_len )
476  return -1;
477
478 // now we know everything is complet we can start to extract data...
479
480 *len = 0;
481
482 memset(event, 0, sizeof(struct roar_event));
483
484 if ( flags & ROAR_EVENT_NETFLAG_PROXYEVENT ) {
485  flags -= ROAR_EVENT_NETFLAG_PROXYEVENT;
486  event->flags |= ROAR_EVENT_FLAG_PROXYEVENT;
487 }
488
489 if ( flags & ROAR_EVENT_NETFLAG_DATA ) {
490  flags -= ROAR_EVENT_NETFLAG_DATA;
491  event->flags |= ROAR_EVENT_FLAG_NETTRANS;
492 }
493
494 // test if there are flags left we do not understand:
495 if ( flags ) {
496  return -1;
497 }
498
499 event->event = ROAR_NET2HOST32(u32[1]);
500
501 if ( event->flags & ROAR_EVENT_FLAG_PROXYEVENT )
502  event->event_proxy = ROAR_NET2HOST32(u32[2]);
503
504 event->emitter     = ROAR_NET2HOST16(u16[0]);
505 event->target      = ROAR_NET2HOST16(u16[1]);
506 event->target_type = ROAR_NET2HOST16(u16[2]);
507 event->arg2_len    = ROAR_NET2HOST16(u16[3]);
508
509 if ( event->emitter == (uint16_t)-1)
510  event->emitter = -1;
511
512 if ( event->target == (uint16_t)-1)
513  event->target = -1;
514
515 if ( event->target_type == (uint16_t)-1)
516  event->target_type = -1;
517
518 if ( event->flags & ROAR_EVENT_FLAG_NETTRANS ) {
519  event->arg0 = ROAR_NET2HOST16(u16[4]);
520  event->arg1 = ROAR_NET2HOST16(u16[5]);
521
522  if ( event->arg0 == (uint16_t)-1)
523   event->arg0 = -1;
524
525  if ( event->arg1 == (uint16_t)-1)
526   event->arg1 = -1;
527
528  event->arg2 = blob + needed_len - event->arg2_len;
529 } else {
530  event->arg0 = -1;
531  event->arg1 = -1;
532  event->arg2 = NULL;
533 }
534
535 *len = needed_len;
536
537 return 0;
538}
539
540
541//ll
Note: See TracBrowser for help on using the repository browser.