gusimplewhiteboard
guwhiteboardwatcher.h
Go to the documentation of this file.
1/*
2 * guwhiteboardwatcher.h
3 *
4 * Created by Carl Lusty in 2013.
5 * Copyright (c) 2013 Carl Lusty
6 * All rights reserved.
7 */
8
9#ifndef GENERIC_WB_WATCHER_H
10#define GENERIC_WB_WATCHER_H
11
12#pragma clang diagnostic push
13#pragma clang diagnostic ignored "-Wweak-vtables"
14#pragma clang diagnostic ignored "-Wpadded"
15#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
16#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
17#pragma clang diagnostic ignored "-Wunused-value"
18
20#include "gusimplewhiteboard.h"
21
22#ifndef WITHOUT_LIBDISPATCH // requires libdispatch at the moment
23
24#include "WBFunctor.h"
25#include <iostream> //cerr
26#include <cstdio> //stderr etc..
27#include <list> //local sub std::list
28
29#ifdef bool
30#undef bool
31#endif
32
33#ifdef true
34#undef true
35#undef false
36#endif
37
38#include <dispatch/dispatch.h>
39
40#define DISPATCH_QUEUE_NAME_WB "guWhiteboard"
41
42#ifndef DISPATCH_QUEUE_SERIAL
43#define DISPATCH_QUEUE_SERIAL NULLPTR
44#endif
45
46#define SUBSCRIBE(wb, t, c, f) ((wb)->subscribe(t ## _WBFunctor<c>::bind(this, &f, k##t ## _v)))
47
48#define WBTYPES_NS CPP_WHITEBOARD_NAMESPACE::C_WBTYPES
49
51
52static void subscription_callback(gu_simple_whiteboard_descriptor *wbd);
53
57struct callback_helper //struct passed to do_callback
58{
61 int offs;
62 uint16_t t_overwrite;
64 uint8_t gen_to_use;
65
67 callback_helper(gu_simple_whiteboard *w, int o, WBFunctorBase *d, uint16_t t, bool use_t, uint8_t gen): wb(w), f(d), offs(o), t_overwrite(t), use_type_overwrite(use_t), gen_to_use(gen) {}
68};
69
70static void do_callback(void *m) //makes the callback call, via GCD queue
71{
72 callback_helper *h = static_cast<callback_helper *>(m);
73
75 h->f->call(static_cast<WBTYPES_NS>(h->t_overwrite), &h->wb->messages[h->offs][h->gen_to_use]);
76 else
77 h->f->call(&h->wb->messages[h->offs][h->gen_to_use]);
78 delete h;
79}
80
105{
107 std::list<WBFunctorBase *> _sub;
108 dispatch_group_t callback_group; // wait for all callbacks to have finished
109 dispatch_queue_t callback_queue; // subscription callback queue
110 u_int16_t local_event_counters[GSW_TOTAL_MESSAGE_TYPES]; // local event counter for all types, used by the global subscription
111
112public:
118 {
119 _wbd = wbd;
120 if(!_wbd)
121 {
123 }
124
125
126 if (!(callback_group = dispatch_group_create()))
127 {
128 std::cerr << "Unable to create dispatch group" << std::endl;
129 throw "Whiteboard cannot create callback queue";
130 }
131 if (!(callback_queue = dispatch_queue_create(DISPATCH_QUEUE_NAME_WB, DISPATCH_QUEUE_SERIAL)))
132 {
133 std::cerr << "Unable to create dispatch queue" << std::endl;
134 throw "Whiteboard cannot create dispatch queue";
135 }
136
137 _wbd->context = this;
138 _wbd->callback = subscription_callback;
139 }
140
145 {
146 _wbd->exit_monitor = true;
147 _wbd->callback = NULLPTR; // avoid starvation
148 dispatch_group_wait(callback_group, DISPATCH_TIME_FOREVER);
149
150 if (_wbd) gsw_free_whiteboard(_wbd);
151#if !defined(__clang__)
152#ifndef __has_feature
153#define __has_feature(x) 0
154#endif
155#endif
156#if !__has_feature(objc_arc)
157 dispatch_release(callback_queue);
158 dispatch_release(callback_group);
159#endif
160 }
161
167 {
168 if(!func->is_simple_wb_version())
169 {
170 fprintf(stderr, "whiteboard_watcher: Only use WB_BIND for the original Whiteboard class, for the simplewhiteboard watcher please use WB_TYPE_BIND(type const enum, function pointer). This is not optional, exiting...\n");
171 exit(1);
172 }
173
175
176 func->set_event_count(_wbd->wb->event_counters[func->type()]);
177 _sub.push_back(func); //Kept locally for actually making the callbacks
178
180 {
181 for (int i = 0; i < GSW_TOTAL_MESSAGE_TYPES; i++) //get current event counts for all types
182 {
183 local_event_counters[i] = _wbd->wb->event_counters[i]; //Already set to zeros in wb constructor memset
184 }
185 }
186
188
190 gsw_add_process(_wbd, getpid());
191 }
192
198 {
200
201 for (std::list<WBFunctorBase *>::iterator i = _sub.begin(); i != _sub.end(); i++)
202 {
203 WBFunctorBase *f = *i;
204 WBTYPES_NS offs = f->type();
205 if (offs == t)
206 {
207 _sub.erase(i);
208 break;
209 }
210 }
211 if (!_sub.size()) gsw_remove_process(_wbd, getpid());
212
214 }
215
220 {
221 static int lastmsg;
222 gu_simple_whiteboard *wb = _wbd->wb;
224 for (std::list<WBFunctorBase *>::iterator i = _sub.begin(); i != _sub.end(); i++)
225 {
226 WBFunctorBase *f = *i;
227 int offs = static_cast<int>(f->type());
228 uint16_t event_count = f->get_event_count();
229
230 /*
231 * offs == -1 means all types "*", otherwise only check
232 * new postings for a specific message type
233 */
235 for (int e = 0; e < GSW_TOTAL_MESSAGE_TYPES; e++) // check all message type event counters
236 {
237 if (local_event_counters[e] != wb->event_counters[e]) //check for new event using event counters
238 {
239 if(local_event_counters[e]+1 != wb->event_counters[e])
240 {
241 fputc('*', stderr);
242 if (lastmsg != e)
243 fprintf(stderr, " @%d\n", e);
244 lastmsg = e;
245 }
246 local_event_counters[e] = wb->event_counters[e];
247 uint16_t t_overwrite = uint16_t(e);
248 callback_helper *h = new callback_helper(wb, e, f, t_overwrite, true, wb->indexes[e]);
249 dispatch_group_async_f(callback_group, callback_queue, h, do_callback);
250 }
251 }
252 else
253 if (event_count != wb->event_counters[offs]) //check for new event using event counters
254 {
255 if(event_count+1 != wb->event_counters[offs])
256 {
257 fputc('*', stderr);
258 if (lastmsg != offs)
259 fprintf(stderr, " @%d\n", offs);
260 lastmsg = offs;
261 }
262 f->set_event_count(wb->event_counters[offs]);
263 callback_helper *h = new callback_helper(wb, offs, f, 0, false, wb->indexes[offs]);
264 dispatch_group_async_f(callback_group, callback_queue, h, do_callback);
265 }
266 }
268 }
269};
270
275static void subscription_callback(gu_simple_whiteboard_descriptor *wbd) //called by simplewhiteboard whenever the global event count increases
276{
277 whiteboard_watcher *self = static_cast<whiteboard_watcher *>(wbd->context);
278 if (self) self->receive_callback();
279}
280
281
282#endif // WITHOUT_LIBDISPATCH
283#endif //GENERIC_WB_WATCHER_H
Base class for WBFunctor.
Definition: WBFunctor.h:41
virtual void call(std::string s, WBMsg *m)=0
Call method for the OLD whiteboard callbacks that used WBMsg - Deprecated.
virtual guWhiteboard::wb_types type()=0
getter for the WB type
virtual uint16_t get_event_count()=0
getter for the WB event counter
virtual void set_event_count(uint16_t e)=0
setter for the WB event counter
virtual bool is_simple_wb_version()=0
is this being used by the 'simple whiteboard' or the OLD whiteboard (which is now Deprecated)
This class provides a subscription implementation for the 'simple' whiteboard, aka the 'typed' whiteb...
void receive_callback()
Internal function, this is what gets triggered by the underlying whiteboard, it then checks its list ...
void subscribe(WBFunctorBase *func)
Allows you to subscribe to a specific whiteboard type and get callbacks when that type is updated.
void unsubscribe(guWhiteboard ::wb_types t)
Stop getting callbacks for a particular whiteboard type.
whiteboard_watcher(gu_simple_whiteboard_descriptor *wbd=NULLPTR)
Constructor, sets up the dispatch queues for handling callbacks.
~whiteboard_watcher()
Destructor, release whiteboard objects and dispatch queues.
void gsw_add_wbd_signal_handler(gu_simple_whiteboard_descriptor *wbd)
add subscription signal handler
void gsw_free_whiteboard(gu_simple_whiteboard_descriptor *wbd)
free the given whiteboard descriptor
gu_simple_whiteboard_descriptor * get_local_singleton_whiteboard(void)
create a simple whiteboard for the local singleton wb pointer
int gsw_procure(gsw_sema_t sem, enum gsw_semaphores s)
grab a whiteboard semaphore
void gsw_remove_process(gu_simple_whiteboard_descriptor *wbd, const pid_t proc)
remove process for subscription signalling
int gsw_vacate(gsw_sema_t sem, enum gsw_semaphores s)
release a whiteboard semaphore
void gsw_add_process(gu_simple_whiteboard_descriptor *wbd, const pid_t proc)
add process for subscription signalling
#define u_int16_t
#define GSW_TOTAL_MESSAGE_TYPES
message types (max)
@ GSW_SEM_CALLBACK
semaphore for callback data
#define kwb_reserved_SubscribeToAllTypes_v
#define DISPATCH_QUEUE_SERIAL
#define WBTYPES_NS
#define DISPATCH_QUEUE_NAME_WB
gu_simple_whiteboard_descriptor * local_whiteboard_descriptor
An internal stuct for passing callback information to dispatch queues.
WBFunctorBase * f
callback functor pointer
uint8_t gen_to_use
the message generation slot that contains the data for this callback
uint16_t t_overwrite
the type offset / enum value to 'fake' see comment for 'use_type_overwrite'
callback_helper(gu_simple_whiteboard *w, int o, WBFunctorBase *d, uint16_t t, bool use_t, uint8_t gen)
Constructor.
int offs
type offset in shared memory, aka type enum value
bool use_type_overwrite
use the type overwrite of WBFunctor (used by the simpleposter to 'fake' messages without a huge amoun...
gu_simple_whiteboard * wb
wb pointer
the actual whiteboard in shared mem
uint8_t indexes[512]
ring buffer indexes
uint16_t event_counters[512]
event counter loops
gu_simple_message messages[512][4]
the actual messages stored in the whiteboard
the underlying whiteboard object
bool exit_monitor
exit the monitor
gsw_subscription_f callback
subscription callback function
void * context
callback context
gsw_sema_t sem
semaphore to use
gu_simple_whiteboard * wb
the actual whiteboard in shared mem