1 /* Copyright (c) 2011, Code Aurora Forum. 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 Code Aurora Forum, Inc. 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
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_destroy
142
143 ===========================================================================*/
msg_q_destroy(void ** msg_q_data)144 msq_q_err_type msg_q_destroy(void** msg_q_data)
145 {
146 if( msg_q_data == NULL )
147 {
148 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
149 return eMSG_Q_INVALID_HANDLE;
150 }
151
152 msg_q* p_msg_q = (msg_q*)*msg_q_data;
153
154 linked_list_destroy(&p_msg_q->msg_list);
155 pthread_mutex_destroy(&p_msg_q->list_mutex);
156 pthread_cond_destroy(&p_msg_q->list_cond);
157
158 p_msg_q->unblocked = 0;
159
160 free(*msg_q_data);
161 *msg_q_data = NULL;
162
163 return eMSG_Q_SUCCESS;
164 }
165
166 /*===========================================================================
167
168 FUNCTION: msg_q_snd
169
170 ===========================================================================*/
msg_q_snd(void * msg_q_data,void * msg_obj,void (* dealloc)(void *))171 msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
172 {
173 msq_q_err_type rv;
174 if( msg_q_data == NULL )
175 {
176 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
177 return eMSG_Q_INVALID_HANDLE;
178 }
179 if( msg_obj == NULL )
180 {
181 LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
182 return eMSG_Q_INVALID_PARAMETER;
183 }
184
185 msg_q* p_msg_q = (msg_q*)msg_q_data;
186
187 pthread_mutex_lock(&p_msg_q->list_mutex);
188 LOC_LOGD("%s: Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
189
190 if( p_msg_q->unblocked )
191 {
192 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
193 pthread_mutex_unlock(&p_msg_q->list_mutex);
194 return eMSG_Q_UNAVAILABLE_RESOURCE;
195 }
196
197 rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
198
199 /* Show data is in the message queue. */
200 pthread_cond_signal(&p_msg_q->list_cond);
201
202 pthread_mutex_unlock(&p_msg_q->list_mutex);
203
204 LOC_LOGD("%s: Finished Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
205
206 return rv;
207 }
208
209 /*===========================================================================
210
211 FUNCTION: msg_q_rcv
212
213 ===========================================================================*/
msg_q_rcv(void * msg_q_data,void ** msg_obj)214 msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
215 {
216 msq_q_err_type rv;
217 if( msg_q_data == NULL )
218 {
219 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
220 return eMSG_Q_INVALID_HANDLE;
221 }
222
223 if( msg_obj == NULL )
224 {
225 LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
226 return eMSG_Q_INVALID_PARAMETER;
227 }
228
229 msg_q* p_msg_q = (msg_q*)msg_q_data;
230
231 LOC_LOGD("%s: Waiting on message\n", __FUNCTION__);
232
233 pthread_mutex_lock(&p_msg_q->list_mutex);
234
235 if( p_msg_q->unblocked )
236 {
237 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
238 pthread_mutex_unlock(&p_msg_q->list_mutex);
239 return eMSG_Q_UNAVAILABLE_RESOURCE;
240 }
241
242 /* Wait for data in the message queue */
243 while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
244 {
245 pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
246 }
247
248 rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
249
250 pthread_mutex_unlock(&p_msg_q->list_mutex);
251
252 LOC_LOGD("%s: Received message %p rv = %d\n", __FUNCTION__, *msg_obj, rv);
253
254 return rv;
255 }
256
257 /*===========================================================================
258
259 FUNCTION: msg_q_flush
260
261 ===========================================================================*/
msg_q_flush(void * msg_q_data)262 msq_q_err_type msg_q_flush(void* msg_q_data)
263 {
264 msq_q_err_type rv;
265 if ( msg_q_data == NULL )
266 {
267 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
268 return eMSG_Q_INVALID_HANDLE;
269 }
270
271 msg_q* p_msg_q = (msg_q*)msg_q_data;
272
273 LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
274
275 pthread_mutex_lock(&p_msg_q->list_mutex);
276
277 /* Remove all elements from the list */
278 rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
279
280 pthread_mutex_unlock(&p_msg_q->list_mutex);
281
282 LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
283
284 return rv;
285 }
286
287 /*===========================================================================
288
289 FUNCTION: msg_q_unblock
290
291 ===========================================================================*/
msg_q_unblock(void * msg_q_data)292 msq_q_err_type msg_q_unblock(void* msg_q_data)
293 {
294 if ( msg_q_data == NULL )
295 {
296 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
297 return eMSG_Q_INVALID_HANDLE;
298 }
299
300 msg_q* p_msg_q = (msg_q*)msg_q_data;
301 pthread_mutex_lock(&p_msg_q->list_mutex);
302
303 if( p_msg_q->unblocked )
304 {
305 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
306 pthread_mutex_unlock(&p_msg_q->list_mutex);
307 return eMSG_Q_UNAVAILABLE_RESOURCE;
308 }
309
310 LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
311 /* Unblocking message queue */
312 p_msg_q->unblocked = 1;
313
314 /* Allow all the waiters to wake up */
315 pthread_cond_broadcast(&p_msg_q->list_cond);
316
317 pthread_mutex_unlock(&p_msg_q->list_mutex);
318
319 LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
320
321 return eMSG_Q_SUCCESS;
322 }
323