1//
2// TimedNotificationQueue.cpp
3//
4// Library: Foundation
5// Package: Notifications
6// Module: TimedNotificationQueue
7//
8// Copyright (c) 2009, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/TimedNotificationQueue.h"
16#include "Poco/Notification.h"
17#include <limits>
18
19
20namespace Poco {
21
22
23TimedNotificationQueue::TimedNotificationQueue()
24{
25}
26
27
28TimedNotificationQueue::~TimedNotificationQueue()
29{
30 try
31 {
32 clear();
33 }
34 catch (...)
35 {
36 poco_unexpected();
37 }
38}
39
40
41void TimedNotificationQueue::enqueueNotification(Notification::Ptr pNotification, Timestamp timestamp)
42{
43 poco_check_ptr (pNotification);
44
45 Timestamp tsNow;
46 Clock clock;
47 Timestamp::TimeDiff diff = timestamp - tsNow;
48 clock += diff;
49
50 FastMutex::ScopedLock lock(_mutex);
51 _nfQueue.insert(NfQueue::value_type(clock, pNotification));
52 _nfAvailable.set();
53}
54
55
56void TimedNotificationQueue::enqueueNotification(Notification::Ptr pNotification, Clock clock)
57{
58 poco_check_ptr (pNotification);
59
60 FastMutex::ScopedLock lock(_mutex);
61 _nfQueue.insert(NfQueue::value_type(clock, pNotification));
62 _nfAvailable.set();
63}
64
65
66Notification* TimedNotificationQueue::dequeueNotification()
67{
68 FastMutex::ScopedLock lock(_mutex);
69
70 NfQueue::iterator it = _nfQueue.begin();
71 if (it != _nfQueue.end())
72 {
73 Clock::ClockDiff sleep = -it->first.elapsed();
74 if (sleep <= 0)
75 {
76 Notification::Ptr pNf = it->second;
77 _nfQueue.erase(it);
78 return pNf.duplicate();
79 }
80 }
81 return 0;
82}
83
84
85Notification* TimedNotificationQueue::waitDequeueNotification()
86{
87 for (;;)
88 {
89 _mutex.lock();
90 NfQueue::iterator it = _nfQueue.begin();
91 if (it != _nfQueue.end())
92 {
93 _mutex.unlock();
94 Clock::ClockDiff sleep = -it->first.elapsed();
95 if (sleep <= 0)
96 {
97 return dequeueOne(it).duplicate();
98 }
99 else if (!wait(sleep))
100 {
101 return dequeueOne(it).duplicate();
102 }
103 else continue;
104 }
105 else
106 {
107 _mutex.unlock();
108 }
109 _nfAvailable.wait();
110 }
111}
112
113
114Notification* TimedNotificationQueue::waitDequeueNotification(long milliseconds)
115{
116 while (milliseconds >= 0)
117 {
118 _mutex.lock();
119 NfQueue::iterator it = _nfQueue.begin();
120 if (it != _nfQueue.end())
121 {
122 _mutex.unlock();
123 Clock now;
124 Clock::ClockDiff sleep = it->first - now;
125 if (sleep <= 0)
126 {
127 return dequeueOne(it).duplicate();
128 }
129 else if (sleep <= 1000*Clock::ClockDiff(milliseconds))
130 {
131 if (!wait(sleep))
132 {
133 return dequeueOne(it).duplicate();
134 }
135 else
136 {
137 milliseconds -= static_cast<long>((now.elapsed() + 999)/1000);
138 continue;
139 }
140 }
141 }
142 else
143 {
144 _mutex.unlock();
145 }
146 if (milliseconds > 0)
147 {
148 Clock now;
149 _nfAvailable.tryWait(milliseconds);
150 milliseconds -= static_cast<long>((now.elapsed() + 999)/1000);
151 }
152 else return 0;
153 }
154 return 0;
155}
156
157
158bool TimedNotificationQueue::wait(Clock::ClockDiff interval)
159{
160 const Clock::ClockDiff MAX_SLEEP = 8*60*60*Clock::ClockDiff(1000000); // sleep at most 8 hours at a time
161 while (interval > 0)
162 {
163 Clock now;
164 Clock::ClockDiff sleep = interval <= MAX_SLEEP ? interval : MAX_SLEEP;
165 if (_nfAvailable.tryWait(static_cast<long>((sleep + 999)/1000)))
166 return true;
167 interval -= now.elapsed();
168 }
169 return false;
170}
171
172
173bool TimedNotificationQueue::empty() const
174{
175 FastMutex::ScopedLock lock(_mutex);
176 return _nfQueue.empty();
177}
178
179
180int TimedNotificationQueue::size() const
181{
182 FastMutex::ScopedLock lock(_mutex);
183 return static_cast<int>(_nfQueue.size());
184}
185
186
187void TimedNotificationQueue::clear()
188{
189 FastMutex::ScopedLock lock(_mutex);
190 _nfQueue.clear();
191}
192
193
194Notification::Ptr TimedNotificationQueue::dequeueOne(NfQueue::iterator& it)
195{
196 FastMutex::ScopedLock lock(_mutex);
197 Notification::Ptr pNf = it->second;
198 _nfQueue.erase(it);
199 return pNf;
200}
201
202
203} // namespace Poco
204