1 /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation, nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "msg_q.h"
30
31 #define LOG_TAG "LocSvc_utils_q"
32 #include "log_util.h"
33 #include "platform_lib_includes.h"
34 #include "linked_list.h"
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <pthread.h>
38
39 typedef struct msg_q {
40 void* msg_list; /* Linked list to store information */
41 pthread_cond_t list_cond; /* Condition variable for waiting on msg queue */
42 pthread_mutex_t list_mutex; /* Mutex for exclusive access to message queue */
43 int unblocked; /* Has this message queue been unblocked? */
44 } msg_q;
45
46 /*===========================================================================
47 FUNCTION convert_linked_list_err_type
48
49 DESCRIPTION
50 Converts from one set of enum values to another.
51
52 linked_list_val: Value to convert to msg_q_enum_type
53
54 DEPENDENCIES
55 N/A
56
57 RETURN VALUE
58 Corresponding linked_list_enum_type in msg_q_enum_type
59
60 SIDE EFFECTS
61 N/A
62
63 ===========================================================================*/
convert_linked_list_err_type(linked_list_err_type linked_list_val)64 static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val)
65 {
66 switch( linked_list_val )
67 {
68 case eLINKED_LIST_SUCCESS:
69 return eMSG_Q_SUCCESS;
70 case eLINKED_LIST_INVALID_PARAMETER:
71 return eMSG_Q_INVALID_PARAMETER;
72 case eLINKED_LIST_INVALID_HANDLE:
73 return eMSG_Q_INVALID_HANDLE;
74 case eLINKED_LIST_UNAVAILABLE_RESOURCE:
75 return eMSG_Q_UNAVAILABLE_RESOURCE;
76 case eLINKED_LIST_INSUFFICIENT_BUFFER:
77 return eMSG_Q_INSUFFICIENT_BUFFER;
78
79 case eLINKED_LIST_FAILURE_GENERAL:
80 default:
81 return eMSG_Q_FAILURE_GENERAL;
82 }
83 }
84
85 /* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
86
87 /*===========================================================================
88
89 FUNCTION: msg_q_init
90
91 ===========================================================================*/
msg_q_init(void ** msg_q_data)92 msq_q_err_type msg_q_init(void** msg_q_data)
93 {
94 if( msg_q_data == NULL )
95 {
96 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
97 return eMSG_Q_INVALID_PARAMETER;
98 }
99
100 msg_q* tmp_msg_q;
101 tmp_msg_q = (msg_q*)calloc(1, sizeof(msg_q));
102 if( tmp_msg_q == NULL )
103 {
104 LOC_LOGE("%s: Unable to allocate space for message queue!\n", __FUNCTION__);
105 return eMSG_Q_FAILURE_GENERAL;
106 }
107
108 if( linked_list_init(&tmp_msg_q->msg_list) != 0 )
109 {
110 LOC_LOGE("%s: Unable to initialize storage list!\n", __FUNCTION__);
111 free(tmp_msg_q);
112 return eMSG_Q_FAILURE_GENERAL;
113 }
114
115 if( pthread_mutex_init(&tmp_msg_q->list_mutex, NULL) != 0 )
116 {
117 LOC_LOGE("%s: Unable to initialize list mutex!\n", __FUNCTION__);
118 linked_list_destroy(&tmp_msg_q->msg_list);
119 free(tmp_msg_q);
120 return eMSG_Q_FAILURE_GENERAL;
121 }
122
123 if( pthread_cond_init(&tmp_msg_q->list_cond, NULL) != 0 )
124 {
125 LOC_LOGE("%s: Unable to initialize msg q cond var!\n", __FUNCTION__);
126 linked_list_destroy(&tmp_msg_q->msg_list);
127 pthread_mutex_destroy(&tmp_msg_q->list_mutex);
128 free(tmp_msg_q);
129 return eMSG_Q_FAILURE_GENERAL;
130 }
131
132 tmp_msg_q->unblocked = 0;
133
134 *msg_q_data = tmp_msg_q;
135
136 return eMSG_Q_SUCCESS;
137 }
138
139 /*===========================================================================
140
141 FUNCTION: msg_q_init2
142
143 ===========================================================================*/
msg_q_init2()144 const void* msg_q_init2()
145 {
146 void* q = NULL;
147 if (eMSG_Q_SUCCESS != msg_q_init(&q)) {
148 q = NULL;
149 }
150 return q;
151 }
152
153 /*===========================================================================
154
155 FUNCTION: msg_q_destroy
156
157 ===========================================================================*/
msg_q_destroy(void ** msg_q_data)158 msq_q_err_type msg_q_destroy(void** msg_q_data)
159 {
160 if( msg_q_data == NULL )
161 {
162 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
163 return eMSG_Q_INVALID_HANDLE;
164 }
165
166 msg_q* p_msg_q = (msg_q*)*msg_q_data;
167
168 linked_list_destroy(&p_msg_q->msg_list);
169 pthread_mutex_destroy(&p_msg_q->list_mutex);
170 pthread_cond_destroy(&p_msg_q->list_cond);
171
172 p_msg_q->unblocked = 0;
173
174 free(*msg_q_data);
175 *msg_q_data = NULL;
176
177 return eMSG_Q_SUCCESS;
178 }
179
180 /*===========================================================================
181
182 FUNCTION: msg_q_snd
183
184 ===========================================================================*/
msg_q_snd(void * msg_q_data,void * msg_obj,void (* dealloc)(void *))185 msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
186 {
187 msq_q_err_type rv;
188 if( msg_q_data == NULL )
189 {
190 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
191 return eMSG_Q_INVALID_HANDLE;
192 }
193 if( msg_obj == NULL )
194 {
195 LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
196 return eMSG_Q_INVALID_PARAMETER;
197 }
198
199 msg_q* p_msg_q = (msg_q*)msg_q_data;
200
201 pthread_mutex_lock(&p_msg_q->list_mutex);
202 LOC_LOGV("%s: Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
203
204 if( p_msg_q->unblocked )
205 {
206 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
207 pthread_mutex_unlock(&p_msg_q->list_mutex);
208 return eMSG_Q_UNAVAILABLE_RESOURCE;
209 }
210
211 rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
212
213 /* Show data is in the message queue. */
214 pthread_cond_signal(&p_msg_q->list_cond);
215
216 pthread_mutex_unlock(&p_msg_q->list_mutex);
217
218 LOC_LOGV("%s: Finished Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
219
220 return rv;
221 }
222
223 /*===========================================================================
224
225 FUNCTION: msg_q_rcv
226
227 ===========================================================================*/
msg_q_rcv(void * msg_q_data,void ** msg_obj)228 msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
229 {
230 msq_q_err_type rv;
231 if( msg_q_data == NULL )
232 {
233 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
234 return eMSG_Q_INVALID_HANDLE;
235 }
236
237 if( msg_obj == NULL )
238 {
239 LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
240 return eMSG_Q_INVALID_PARAMETER;
241 }
242
243 msg_q* p_msg_q = (msg_q*)msg_q_data;
244
245 LOC_LOGV("%s: Waiting on message\n", __FUNCTION__);
246
247 pthread_mutex_lock(&p_msg_q->list_mutex);
248
249 if( p_msg_q->unblocked )
250 {
251 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
252 pthread_mutex_unlock(&p_msg_q->list_mutex);
253 return eMSG_Q_UNAVAILABLE_RESOURCE;
254 }
255
256 /* Wait for data in the message queue */
257 while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
258 {
259 pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
260 }
261
262 rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
263
264 pthread_mutex_unlock(&p_msg_q->list_mutex);
265
266 LOC_LOGV("%s: Received message 0x%08X rv = %d\n", __FUNCTION__, *msg_obj, rv);
267
268 return rv;
269 }
270
271 /*===========================================================================
272
273 FUNCTION: msg_q_flush
274
275 ===========================================================================*/
msg_q_flush(void * msg_q_data)276 msq_q_err_type msg_q_flush(void* msg_q_data)
277 {
278 msq_q_err_type rv;
279 if ( msg_q_data == NULL )
280 {
281 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
282 return eMSG_Q_INVALID_HANDLE;
283 }
284
285 msg_q* p_msg_q = (msg_q*)msg_q_data;
286
287 LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
288
289 pthread_mutex_lock(&p_msg_q->list_mutex);
290
291 /* Remove all elements from the list */
292 rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
293
294 pthread_mutex_unlock(&p_msg_q->list_mutex);
295
296 LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
297
298 return rv;
299 }
300
301 /*===========================================================================
302
303 FUNCTION: msg_q_unblock
304
305 ===========================================================================*/
msg_q_unblock(void * msg_q_data)306 msq_q_err_type msg_q_unblock(void* msg_q_data)
307 {
308 if ( msg_q_data == NULL )
309 {
310 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
311 return eMSG_Q_INVALID_HANDLE;
312 }
313
314 msg_q* p_msg_q = (msg_q*)msg_q_data;
315 pthread_mutex_lock(&p_msg_q->list_mutex);
316
317 if( p_msg_q->unblocked )
318 {
319 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
320 pthread_mutex_unlock(&p_msg_q->list_mutex);
321 return eMSG_Q_UNAVAILABLE_RESOURCE;
322 }
323
324 LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
325 /* Unblocking message queue */
326 p_msg_q->unblocked = 1;
327
328 /* Allow all the waiters to wake up */
329 pthread_cond_broadcast(&p_msg_q->list_cond);
330
331 pthread_mutex_unlock(&p_msg_q->list_mutex);
332
333 LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
334
335 return eMSG_Q_SUCCESS;
336 }
337