Syncmsg.h
Go to the documentation of this file.
1// -*- C++ -*-
2// Copyright (c) 2005-2010, Isode Limited, London, England.
3// All rights reserved.
4//
5// Acquisition and use of this software and related materials for any
6// purpose requires a written licence agreement from Isode Limited,
7// or a written licence from an organisation licenced by Isode Limited
8// to grant such a licence.
9
10
11//
12//
18//
19// @VERSION@
20
21#ifndef _SYNCMSG_H_
22#define _SYNCMSG_H_
23
24#include <errno.h>
25#include <pthread.h>
26#include "timeutil.h"
27#include "EventSvc.h"
28
30template<class M, class C> class SyncEvent : public Event::AsyncEvent {
31 private:
32 M _msg;
33 C *_target;
34 bool _onheap;
35
36 public:
38 inline SyncEvent () : _target(0), _onheap(0) {}
39
41 inline SyncEvent (M *msg, C *target) :
42 _msg (*msg), _target(target), _onheap(true) { }
43
45 virtual ~SyncEvent () { }
46
48 inline void Init (C *rcvr) {
49 SetReceiver (rcvr);
50 _target = rcvr;
51 }
52
54 void Deliver () override {
55 _target->actualDeliver (&_msg);
56 }
57
59 bool ShouldDelete () const override { return _onheap; }
60
62 inline void Send (M &data) {
63 _msg = data;
64 ::Event::Manager::GetManager()->Queue (this);
65 }
66
68 inline void Send (const timespec *when, M &data ) {
69 _msg = data;
70
71 ::Event::Manager::GetManager()->QueueAt (this, when);
72 }
73
75 inline void Sendms (unsigned millisecs, M &data) {
76 _msg = data;
77
78 ::Event::Manager::GetManager()->QueueAt (this, millisecs);
79 }
80
82 inline void SendAtExit (M &data) {
83 _msg = data;
84 ::Event::Manager::GetManager()->QueueAtExit (this);
85 }
86
87};
88
89
91class SyncEventQueue : Event::AsyncEventRef {
92private:
93 // A simple, doubly linked list
94 SyncEventQueue *_next;
95 SyncEventQueue *_prev;
96 SyncEventQueue *_free;
97 SyncEventQueue **_freelist;
98
99 SyncEventQueue (Event::AsyncEvent *event) : Event::AsyncEventRef (event) {}
100
101public:
102 SyncEventQueue () {
103 _next = _prev = this;
104 _freelist = &_free;
105 _free = 0;
106 }
107
108 ~SyncEventQueue () {
109 // Only delete items if root element
110 if ( _freelist == &_free ) {
111 SyncEventQueue *q1 = _free;
112 while ( q1 ) {
113 SyncEventQueue *q2 = q1;
114 q1 = q1->_free;
115 delete q2;
116 }
117 }
118 }
119
121 void Insert (Event::AsyncEvent *event) {
122 SyncEventQueue *newq = _free;
123
124 if ( newq ) {
125 _free = newq->_free;
126 newq->Set (event);
127 } else {
128 newq = new SyncEventQueue (event);
129 newq->_freelist = _freelist;
130 }
131
132 _prev->_next = newq;
133 newq->_prev = _prev;
134 newq->_next = this;
135 _prev = newq;
136 }
137
139 void extract () override {
140 _prev->_next = _next;
141 _next->_prev = _prev;
142 _free = *_freelist;
143 *_freelist = this;
144 }
145
147 Event::AsyncEvent * First () {
148 if ( _next == this )
149 return 0;
150
151 return _next->Extract();
152 }
153};
154
161//
165#pragma GCC diagnostic push
166#pragma GCC diagnostic ignored "-Wsuggest-override"
167
168template<class C> class Syncmsgobj : public C {
169 private:
170 pthread_mutex_t _mutex;
171 SyncEventQueue _queue;
172 bool _busy;
173 bool _die;
174 bool _dying;
175 int _qcount;
176
177 protected:
178 inline void dieAux () {
179 int rc = pthread_mutex_lock (&_mutex);
180
181 _die = true;
182
183 bool killit = !_busy && !_dying && _qcount <= 0;
184
185 if ( killit )
186 _dying = true;
187
188 if ( rc == 0 ) pthread_mutex_unlock (&_mutex);
189
190 if ( killit ) delete this;
191 }
192
193 public:
194 inline Syncmsgobj () : _busy(false), _die(false), _dying(false), _qcount(0) {
195 pthread_mutex_init (&_mutex, 0);
196 }
197
198 virtual ~Syncmsgobj () {
199 Event::AsyncEvent *item;
200
201 while ( (item = _queue.First()) != 0 )
202 if ( item->ShouldDelete() )
203 delete item;
204
205 pthread_mutex_destroy (&_mutex);
206 }
207
209 // Always in a pair with a Process
210 virtual void Queue (Event::AsyncEvent *event) {
211 if ( pthread_mutex_lock (&_mutex) != 0 )
212 return;
213
214 _queue.Insert (event);
215
216 _qcount++;
217
218 pthread_mutex_unlock (&_mutex);
219 }
220
222 virtual void Extract (Event::AsyncEvent *event) {
223 if ( pthread_mutex_lock (&_mutex) != 0 )
224 return;
225
226 Event::AsyncEventRef *ref = event->Reference();
227
228 if ( ref != 0 )
229 ref->Extract();
230
231 pthread_mutex_unlock (&_mutex);
232 }
233
235 // ALways follows a Queue
236 virtual void Process () {
237 if ( pthread_mutex_lock (&_mutex) != 0 )
238 return;
239
240 _qcount--;
241
242 if ( _busy ) {
243
244 pthread_mutex_unlock (&_mutex);
245
246 return;
247 }
248
249 _busy = true;
250
251 Event::AsyncEvent *item;
252
253 while ( (item = _queue.First ()) ) {
254
255 if ( _die ) {
256 if ( item->ShouldDelete() )
257 delete item;
258 continue;
259 }
260
261 pthread_mutex_unlock (&_mutex);
262
263 // As the delivery of the item may delete the underlying object,
264 // we need to find out whether this should delete it beforehand
265 bool shouldDelete = item->ShouldDelete();
266
267 item->Deliver ();
268
269 if ( shouldDelete )
270 delete item;
271
272 if ( pthread_mutex_lock (&_mutex) != 0 )
273 return;
274 }
275
276 _busy = false;
277
278 bool killit = _die && !_dying && _qcount <= 0;
279
280 if ( killit )
281 _dying = true;
282
283 pthread_mutex_unlock (&_mutex);
284
285 if ( killit )
286 delete this;
287 }
288
290 template <class M> inline void msgDeliver (M *msg) {
291
292 if ( pthread_mutex_lock (&_mutex) != 0 )
293 return;
294
295 if ( _die || _busy ) {
296
297 // Don't bother to queue this message if the entity is going away
298 if ( !_die )
299 _queue.Insert (new SyncEvent<M,C> (msg, this));
300
301 pthread_mutex_unlock (&_mutex);
302
303 return;
304 }
305
306 _busy = true;
307 pthread_mutex_unlock (&_mutex);
308
309 this->actualDeliver (msg);
310
311 if ( pthread_mutex_lock (&_mutex) != 0 )
312 return;
313
314 Event::AsyncEvent *item;
315
316 while ( (item = _queue.First ()) ) {
317
318 if ( _die ) {
319 if ( item->ShouldDelete() )
320 delete item;
321 continue;
322 }
323
324 pthread_mutex_unlock (&_mutex);
325
326 bool shouldDelete = item->ShouldDelete();
327
328 item->Deliver ();
329
330 if ( shouldDelete )
331 delete item;
332
333 if ( pthread_mutex_lock (&_mutex) != 0 )
334 return;
335 }
336
337 _busy = false;
338
339 bool killit = _die && !_dying && _qcount <= 0;
340
341 if ( killit )
342 _dying = true;
343
344 pthread_mutex_unlock (&_mutex);
345
346 if ( killit ) delete this;
347 }
348 #pragma GCC diagnostic pop
349};
350
351#endif /* _SYNCMSG_H_ */
A simple FIFO queue for events.
Definition Syncmsg.h:91
void extract() override
Subordinate extract mechanism.
Definition Syncmsg.h:139
Event::AsyncEvent * First()
Remove first element of queue.
Definition Syncmsg.h:147
void Insert(Event::AsyncEvent *event)
Insert in queue.
Definition Syncmsg.h:121
Class used to wrap each event object type for a given receiver.
Definition Syncmsg.h:30
void Send(M &data)
Send data now.
Definition Syncmsg.h:62
virtual ~SyncEvent()
Destructor must be virtual.
Definition Syncmsg.h:45
void Init(C *rcvr)
Set the target.
Definition Syncmsg.h:48
void Sendms(unsigned millisecs, M &data)
Send in interval (milliseconds)
Definition Syncmsg.h:75
SyncEvent()
Constructor within another object.
Definition Syncmsg.h:38
bool ShouldDelete() const override
Can delete this object.
Definition Syncmsg.h:59
SyncEvent(M *msg, C *target)
Constructor takes message object to be wrapped.
Definition Syncmsg.h:41
void Deliver() override
Deliver this message to the receiver.
Definition Syncmsg.h:54
void Send(const timespec *when, M &data)
Send using timespec.
Definition Syncmsg.h:68
void SendAtExit(M &data)
Send when terminating.
Definition Syncmsg.h:82
Template class for protecting an object.
Definition Syncmsg.h:168
void msgDeliver(M *msg)
template function for delivering message of given type to receiver
Definition Syncmsg.h:290
virtual void Process()
Process queued events for the object.
Definition Syncmsg.h:236
virtual void Queue(Event::AsyncEvent *event)
Queue event from Event Manager.
Definition Syncmsg.h:210
virtual void Extract(Event::AsyncEvent *event)
Remove event from queue.
Definition Syncmsg.h:222
Various utility functions for handling times.

All rights reserved © 2002 - 2024 Isode Ltd.