comparison deps/Platinum/ThirdParty/Neptune/Source/System/Posix/NptPosixQueue.cpp @ 0:3425707ddbf6

Initial import (hopefully this mercurial stuff works...)
author fraserofthenight
date Mon, 06 Jul 2009 08:06:28 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3425707ddbf6
1 /*****************************************************************
2 |
3 | Neptune - Queue :: Posix Implementation
4 |
5 | (c) 2001-2002 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
7 |
8 ****************************************************************/
9
10 /*----------------------------------------------------------------------
11 | includes
12 +---------------------------------------------------------------------*/
13 #if defined(__SYMBIAN32__)
14 #include <stdio.h>
15 #endif
16 #include <pthread.h>
17 #include <time.h>
18 #include <sys/time.h>
19 #if defined(__SYMBIAN32__)
20 #include <errno.h>
21 #else
22 #include <cerrno>
23 #endif
24
25 #include "NptConfig.h"
26 #include "NptTypes.h"
27 #include "NptQueue.h"
28 #include "NptThreads.h"
29 #include "NptList.h"
30 #include "NptLogging.h"
31
32 /*----------------------------------------------------------------------
33 | logging
34 +---------------------------------------------------------------------*/
35 NPT_SET_LOCAL_LOGGER("neptune.queue.posix")
36
37 /*----------------------------------------------------------------------
38 | NPT_PosixQueue
39 +---------------------------------------------------------------------*/
40 class NPT_PosixQueue : public NPT_GenericQueue
41 {
42 public:
43 // methods
44 NPT_PosixQueue(NPT_Cardinal max_items);
45 ~NPT_PosixQueue();
46 NPT_Result Push(NPT_QueueItem* item, NPT_Timeout timeout);
47 NPT_Result Pop(NPT_QueueItem*& item, NPT_Timeout timeout);
48 NPT_Result Peek(NPT_QueueItem*& item, NPT_Timeout timeout);
49
50 private:
51 // members
52 NPT_Cardinal m_MaxItems;
53 pthread_mutex_t m_Mutex;
54 pthread_cond_t m_CanPushCondition;
55 pthread_cond_t m_CanPopCondition;
56 NPT_Cardinal m_PushersWaitingCount;
57 NPT_Cardinal m_PoppersWaitingCount;
58 NPT_List<NPT_QueueItem*> m_Items;
59 };
60
61 /*----------------------------------------------------------------------
62 | NPT_PosixQueue::NPT_PosixQueue
63 +---------------------------------------------------------------------*/
64 NPT_PosixQueue::NPT_PosixQueue(NPT_Cardinal max_items) :
65 m_MaxItems(max_items),
66 m_PushersWaitingCount(0),
67 m_PoppersWaitingCount(0)
68 {
69 NPT_LOG_FINER("NPT_PosixQueue::NPT_PosixQueue");
70
71 pthread_mutex_init(&m_Mutex, NULL);
72 pthread_cond_init(&m_CanPushCondition, NULL);
73 pthread_cond_init(&m_CanPopCondition, NULL);
74 }
75
76 /*----------------------------------------------------------------------
77 | NPT_PosixQueue::~NPT_PosixQueue()
78 +---------------------------------------------------------------------*/
79 NPT_PosixQueue::~NPT_PosixQueue()
80 {
81 // destroy resources
82 pthread_cond_destroy(&m_CanPushCondition);
83 pthread_cond_destroy(&m_CanPopCondition);
84 pthread_mutex_destroy(&m_Mutex);
85 }
86
87 /*----------------------------------------------------------------------
88 | NPT_PosixQueue::Push
89 +---------------------------------------------------------------------*/
90 NPT_Result
91 NPT_PosixQueue::Push(NPT_QueueItem* item, NPT_Timeout timeout)
92 {
93 struct timespec timed;
94 if (timeout != NPT_TIMEOUT_INFINITE) {
95 // get current time from system
96 struct timeval now;
97 if (gettimeofday(&now, NULL)) {
98 return NPT_FAILURE;
99 }
100
101 now.tv_usec += timeout * 1000;
102 if (now.tv_usec >= 1000000) {
103 now.tv_sec += now.tv_usec / 1000000;
104 now.tv_usec = now.tv_usec % 1000000;
105 }
106
107 // setup timeout
108 timed.tv_sec = now.tv_sec;
109 timed.tv_nsec = now.tv_usec * 1000;
110 }
111
112 // lock the mutex that protects the list
113 if (pthread_mutex_lock(&m_Mutex)) {
114 return NPT_FAILURE;
115 }
116
117 NPT_Result result = NPT_SUCCESS;
118 // check that we have not exceeded the max
119 if (m_MaxItems) {
120 while (m_Items.GetItemCount() >= m_MaxItems) {
121 // wait until we can push
122 ++m_PushersWaitingCount;
123 if (timeout == NPT_TIMEOUT_INFINITE) {
124 pthread_cond_wait(&m_CanPushCondition, &m_Mutex);
125 --m_PushersWaitingCount;
126 } else {
127 int wait_res = pthread_cond_timedwait(&m_CanPushCondition,
128 &m_Mutex,
129 &timed);
130 --m_PushersWaitingCount;
131 if (wait_res == ETIMEDOUT) {
132 result = NPT_ERROR_TIMEOUT;
133 break;
134 }
135 }
136 }
137 }
138
139 // add the item to the list
140 if (result == NPT_SUCCESS) {
141 m_Items.Add(item);
142
143 // wake up any thread that may be waiting to pop
144 if (m_PoppersWaitingCount) {
145 pthread_cond_signal(&m_CanPopCondition);
146 }
147 }
148
149 // unlock the mutex
150 pthread_mutex_unlock(&m_Mutex);
151
152 return result;
153 }
154
155 /*----------------------------------------------------------------------
156 | NPT_PosixQueue::Pop
157 +---------------------------------------------------------------------*/
158 NPT_Result
159 NPT_PosixQueue::Pop(NPT_QueueItem*& item, NPT_Timeout timeout)
160 {
161 struct timespec timed;
162 if (timeout != NPT_TIMEOUT_INFINITE) {
163 // get current time from system
164 struct timeval now;
165 if (gettimeofday(&now, NULL)) {
166 return NPT_FAILURE;
167 }
168
169 now.tv_usec += timeout * 1000;
170 if (now.tv_usec >= 1000000) {
171 now.tv_sec += now.tv_usec / 1000000;
172 now.tv_usec = now.tv_usec % 1000000;
173 }
174
175 // setup timeout
176 timed.tv_sec = now.tv_sec;
177 timed.tv_nsec = now.tv_usec * 1000;
178 }
179
180 // lock the mutex that protects the list
181 if (pthread_mutex_lock(&m_Mutex)) {
182 return NPT_FAILURE;
183 }
184
185 NPT_Result result;
186 if (timeout) {
187 while ((result = m_Items.PopHead(item)) == NPT_ERROR_LIST_EMPTY) {
188 // no item in the list, wait for one
189 ++m_PoppersWaitingCount;
190 if (timeout == NPT_TIMEOUT_INFINITE) {
191 pthread_cond_wait(&m_CanPopCondition, &m_Mutex);
192 --m_PoppersWaitingCount;
193 } else {
194 int wait_res = pthread_cond_timedwait(&m_CanPopCondition,
195 &m_Mutex,
196 &timed);
197 --m_PoppersWaitingCount;
198 if (wait_res == ETIMEDOUT) {
199 result = NPT_ERROR_TIMEOUT;
200 break;
201 }
202 }
203 }
204 } else {
205 result = m_Items.PopHead(item);
206 }
207
208 // wake up any thread that my be waiting to push
209 if (m_MaxItems && (result == NPT_SUCCESS) && m_PushersWaitingCount) {
210 pthread_cond_signal(&m_CanPushCondition);
211 }
212
213 // unlock the mutex
214 pthread_mutex_unlock(&m_Mutex);
215
216 return result;
217 }
218
219 /*----------------------------------------------------------------------
220 | NPT_PosixQueue::Peek
221 +---------------------------------------------------------------------*/
222 NPT_Result
223 NPT_PosixQueue::Peek(NPT_QueueItem*& item, NPT_Timeout timeout)
224 {
225 struct timespec timed;
226 if (timeout != NPT_TIMEOUT_INFINITE) {
227 // get current time from system
228 struct timeval now;
229 if (gettimeofday(&now, NULL)) {
230 return NPT_FAILURE;
231 }
232
233 now.tv_usec += timeout * 1000;
234 if (now.tv_usec >= 1000000) {
235 now.tv_sec += now.tv_usec / 1000000;
236 now.tv_usec = now.tv_usec % 1000000;
237 }
238
239 // setup timeout
240 timed.tv_sec = now.tv_sec;
241 timed.tv_nsec = now.tv_usec * 1000;
242 }
243
244 // lock the mutex that protects the list
245 if (pthread_mutex_lock(&m_Mutex)) {
246 return NPT_FAILURE;
247 }
248
249 NPT_Result result = NPT_SUCCESS;
250 NPT_List<NPT_QueueItem*>::Iterator head = m_Items.GetFirstItem();
251 if (timeout) {
252 while (!head) {
253 // no item in the list, wait for one
254 ++m_PoppersWaitingCount;
255 if (timeout == NPT_TIMEOUT_INFINITE) {
256 pthread_cond_wait(&m_CanPopCondition, &m_Mutex);
257 --m_PoppersWaitingCount;
258 } else {
259 int wait_res = pthread_cond_timedwait(&m_CanPopCondition,
260 &m_Mutex,
261 &timed);
262 --m_PoppersWaitingCount;
263 if (wait_res == ETIMEDOUT) {
264 result = NPT_ERROR_TIMEOUT;
265 break;
266 }
267 }
268
269 head = m_Items.GetFirstItem();
270 }
271 } else {
272 if (!head) result = NPT_ERROR_LIST_EMPTY;
273 }
274
275 item = head?*head:NULL;
276
277 // unlock the mutex
278 pthread_mutex_unlock(&m_Mutex);
279
280 return result;
281 }
282
283 /*----------------------------------------------------------------------
284 | NPT_GenericQueue::CreateInstance
285 +---------------------------------------------------------------------*/
286 NPT_GenericQueue*
287 NPT_GenericQueue::CreateInstance(NPT_Cardinal max_items)
288 {
289 NPT_LOG_FINER_1("NPT_GenericQueue::CreateInstance - queue max_items = %ld", max_items);
290 return new NPT_PosixQueue(max_items);
291 }
292
293
294
295