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 virtual void Deliver () {
55 _target->actualDeliver (&_msg);
56 }
57
59 virtual bool ShouldDelete () const { 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 virtual void extract () {
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
166template<class C> class Syncmsgobj : public C {
167 private:
168 pthread_mutex_t _mutex;
169 SyncEventQueue _queue;
170 bool _busy;
171 bool _die;
172 bool _dying;
173 int _qcount;
174
175 protected:
176 inline void dieAux () {
177 int rc = pthread_mutex_lock (&_mutex);
178
179 _die = true;
180
181 bool killit = !_busy && !_dying && _qcount <= 0;
182
183 if ( killit )
184 _dying = true;
185
186 if ( rc == 0 ) pthread_mutex_unlock (&_mutex);
187
188 if ( killit ) delete this;
189 }
190
191 public:
192 inline Syncmsgobj () : _busy(false), _die(false), _dying(false), _qcount(0) {
193 pthread_mutex_init (&_mutex, 0);
194 }
195
196 virtual ~Syncmsgobj () {
197 Event::AsyncEvent *item;
198
199 while ( (item = _queue.First()) != 0 )
200 if ( item->ShouldDelete() )
201 delete item;
202
203 pthread_mutex_destroy (&_mutex);
204 }
205
207 // Always in a pair with a Process
208 virtual void Queue (Event::AsyncEvent *event) {
209 if ( pthread_mutex_lock (&_mutex) != 0 )
210 return;
211
212 _queue.Insert (event);
213
214 _qcount++;
215
216 pthread_mutex_unlock (&_mutex);
217 }
218
220 virtual void Extract (Event::AsyncEvent *event) {
221 if ( pthread_mutex_lock (&_mutex) != 0 )
222 return;
223
224 Event::AsyncEventRef *ref = event->Reference();
225
226 if ( ref != 0 )
227 ref->Extract();
228
229 pthread_mutex_unlock (&_mutex);
230 }
231
233 // ALways follows a Queue
234 virtual void Process () {
235 if ( pthread_mutex_lock (&_mutex) != 0 )
236 return;
237
238 _qcount--;
239
240 if ( _busy ) {
241
242 pthread_mutex_unlock (&_mutex);
243
244 return;
245 }
246
247 _busy = true;
248
249 Event::AsyncEvent *item;
250
251 while ( (item = _queue.First ()) ) {
252
253 if ( _die ) {
254 if ( item->ShouldDelete() )
255 delete item;
256 continue;
257 }
258
259 pthread_mutex_unlock (&_mutex);
260
261 // As the delivery of the item may delete the underlying object,
262 // we need to find out whether this should delete it beforehand
263 bool shouldDelete = item->ShouldDelete();
264
265 item->Deliver ();
266
267 if ( shouldDelete )
268 delete item;
269
270 if ( pthread_mutex_lock (&_mutex) != 0 )
271 return;
272 }
273
274 _busy = false;
275
276 bool killit = _die && !_dying && _qcount <= 0;
277
278 if ( killit )
279 _dying = true;
280
281 pthread_mutex_unlock (&_mutex);
282
283 if ( killit )
284 delete this;
285 }
286
288 template <class M> inline void msgDeliver (M *msg) {
289
290 if ( pthread_mutex_lock (&_mutex) != 0 )
291 return;
292
293 if ( _die || _busy ) {
294
295 // Don't bother to queue this message if the entity is going away
296 if ( !_die )
297 _queue.Insert (new SyncEvent<M,C> (msg, this));
298
299 pthread_mutex_unlock (&_mutex);
300
301 return;
302 }
303
304 _busy = true;
305 pthread_mutex_unlock (&_mutex);
306
307 this->actualDeliver (msg);
308
309 if ( pthread_mutex_lock (&_mutex) != 0 )
310 return;
311
312 Event::AsyncEvent *item;
313
314 while ( (item = _queue.First ()) ) {
315
316 if ( _die ) {
317 if ( item->ShouldDelete() )
318 delete item;
319 continue;
320 }
321
322 pthread_mutex_unlock (&_mutex);
323
324 bool shouldDelete = item->ShouldDelete();
325
326 item->Deliver ();
327
328 if ( shouldDelete )
329 delete item;
330
331 if ( pthread_mutex_lock (&_mutex) != 0 )
332 return;
333 }
334
335 _busy = false;
336
337 bool killit = _die && !_dying && _qcount <= 0;
338
339 if ( killit )
340 _dying = true;
341
342 pthread_mutex_unlock (&_mutex);
343
344 if ( killit ) delete this;
345 }
346};
347
348#endif /* _SYNCMSG_H_ */
A simple FIFO queue for events.
Definition Syncmsg.h:91
virtual void extract()
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
virtual bool ShouldDelete() const
Can delete this object.
Definition Syncmsg.h:59
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
SyncEvent(M *msg, C *target)
Constructor takes message object to be wrapped.
Definition Syncmsg.h:41
virtual void Deliver()
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:166
void msgDeliver(M *msg)
template function for delivering message of given type to receiver
Definition Syncmsg.h:288
virtual void Process()
Process queued events for the object.
Definition Syncmsg.h:234
virtual void Queue(Event::AsyncEvent *event)
Queue event from Event Manager.
Definition Syncmsg.h:208
virtual void Extract(Event::AsyncEvent *event)
Remove event from queue.
Definition Syncmsg.h:220
Various utility functions for handling times.

All rights reserved © 2002 - 2024 Isode Ltd.