Mercurial > projects > hoofbaby
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 |