1 /* Copyright (c) 2011-2012, 2014, 2017 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 <platform_lib_includes.h>
33 #include "linked_list.h"
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <pthread.h>
37
38 typedef struct msg_q {
39 void* msg_list; /* Linked list to store information */
40 pthread_cond_t list_cond; /* Condition variable for waiting on msg queue */
41 pthread_mutex_t list_mutex; /* Mutex for exclusive access to message queue */
42 int unblocked; /* Has this message queue been unblocked? */
43 } msg_q;
44
45 /*===========================================================================
46 FUNCTION convert_linked_list_err_type
47
48 DESCRIPTION
49 Converts from one set of enum values to another.
50
51 linked_list_val: Value to convert to msg_q_enum_type
52
53 DEPENDENCIES
54 N/A
55
56 RETURN VALUE
57 Corresponding linked_list_enum_type in msg_q_enum_type
58
59 SIDE EFFECTS
60 N/A
61
62 ===========================================================================*/
convert_linked_list_err_type(linked_list_err_type linked_list_val)63 static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val)
64 {
65 switch( linked_list_val )
66 {
67 case eLINKED_LIST_SUCCESS:
68 return eMSG_Q_SUCCESS;
69 case eLINKED_LIST_INVALID_PARAMETER:
70 return eMSG_Q_INVALID_PARAMETER;
71 case eLINKED_LIST_INVALID_HANDLE:
72 return eMSG_Q_INVALID_HANDLE;
73 case eLINKED_LIST_UNAVAILABLE_RESOURCE:
74 return eMSG_Q_UNAVAILABLE_RESOURCE;
75 case eLINKED_LIST_INSUFFICIENT_BUFFER:
76 return eMSG_Q_INSUFFICIENT_BUFFER;
77
78 case eLINKED_LIST_FAILURE_GENERAL:
79 default:
80 return eMSG_Q_FAILURE_GENERAL;
81 }
82 }
83
84 /* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
85
86 /*===========================================================================
87
88 FUNCTION: msg_q_init
89
90 ===========================================================================*/
msg_q_init(void ** msg_q_data)91 msq_q_err_type msg_q_init(void** msg_q_data)
92 {
93 if( msg_q_data == NULL )
94 {
95 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
96 return eMSG_Q_INVALID_PARAMETER;
97 }
98
99 msg_q* tmp_msg_q;
100 tmp_msg_q = (msg_q*)calloc(1, sizeof(msg_q));
101 if( tmp_msg_q == NULL )
102 {
103 LOC_LOGE("%s: Unable to allocate space for message queue!\n", __FUNCTION__);
104 return eMSG_Q_FAILURE_GENERAL;
105 }
106
107 if( linked_list_init(&tmp_msg_q->msg_list) != 0 )
108 {
109 LOC_LOGE("%s: Unable to initialize storage list!\n", __FUNCTION__);
110 free(tmp_msg_q);
111 return eMSG_Q_FAILURE_GENERAL;
112 }
113
114 if( pthread_mutex_init(&tmp_msg_q->list_mutex, NULL) != 0 )
115 {
116 LOC_LOGE("%s: Unable to initialize list mutex!\n", __FUNCTION__);
117 linked_list_destroy(&tmp_msg_q->msg_list);
118 free(tmp_msg_q);
119 return eMSG_Q_FAILURE_GENERAL;
120 }
121
122 if( pthread_cond_init(&tmp_msg_q->list_cond, NULL) != 0 )
123 {
124 LOC_LOGE("%s: Unable to initialize msg q cond var!\n", __FUNCTION__);
125 linked_list_destroy(&tmp_msg_q->msg_list);
126 pthread_mutex_destroy(&tmp_msg_q->list_mutex);
127 free(tmp_msg_q);
128 return eMSG_Q_FAILURE_GENERAL;
129 }
130
131 tmp_msg_q->unblocked = 0;
132
133 *msg_q_data = tmp_msg_q;
134
135 return eMSG_Q_SUCCESS;
136 }
137
138 /*===========================================================================
139
140 FUNCTION: msg_q_init2
141
142 ===========================================================================*/
msg_q_init2()143 const void* msg_q_init2()
144 {
145 void* q = NULL;
146 if (eMSG_Q_SUCCESS != msg_q_init(&q)) {
147 q = NULL;
148 }
149 return q;
150 }
151
152 /*===========================================================================
153
154 FUNCTION: msg_q_destroy
155
156 ===========================================================================*/
msg_q_destroy(void ** msg_q_data)157 msq_q_err_type msg_q_destroy(void** msg_q_data)
158 {
159 if( msg_q_data == NULL )
160 {
161 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
162 return eMSG_Q_INVALID_HANDLE;
163 }
164
165 msg_q* p_msg_q = (msg_q*)*msg_q_data;
166
167 linked_list_destroy(&p_msg_q->msg_list);
168 pthread_mutex_destroy(&p_msg_q->list_mutex);
169 pthread_cond_destroy(&p_msg_q->list_cond);
170
171 p_msg_q->unblocked = 0;
172
173 free(*msg_q_data);
174 *msg_q_data = NULL;
175
176 return eMSG_Q_SUCCESS;
177 }
178
179 /*===========================================================================
180
181 FUNCTION: msg_q_snd
182
183 ===========================================================================*/
msg_q_snd(void * msg_q_data,void * msg_obj,void (* dealloc)(void *))184 msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
185 {
186 msq_q_err_type rv;
187 if( msg_q_data == NULL )
188 {
189 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
190 return eMSG_Q_INVALID_HANDLE;
191 }
192 if( msg_obj == NULL )
193 {
194 LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
195 return eMSG_Q_INVALID_PARAMETER;
196 }
197
198 msg_q* p_msg_q = (msg_q*)msg_q_data;
199
200 pthread_mutex_lock(&p_msg_q->list_mutex);
201 LOC_LOGV("%s: Sending message with handle = %p\n", __FUNCTION__, msg_obj);
202
203 if( p_msg_q->unblocked )
204 {
205 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
206 pthread_mutex_unlock(&p_msg_q->list_mutex);
207 return eMSG_Q_UNAVAILABLE_RESOURCE;
208 }
209
210 rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
211
212 /* Show data is in the message queue. */
213 pthread_cond_signal(&p_msg_q->list_cond);
214
215 pthread_mutex_unlock(&p_msg_q->list_mutex);
216
217 LOC_LOGV("%s: Finished Sending message with handle = %p\n", __FUNCTION__, msg_obj);
218
219 return rv;
220 }
221
222 /*===========================================================================
223
224 FUNCTION: msg_q_rcv
225
226 ===========================================================================*/
msg_q_rcv(void * msg_q_data,void ** msg_obj)227 msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
228 {
229 msq_q_err_type rv;
230 if( msg_q_data == NULL )
231 {
232 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
233 return eMSG_Q_INVALID_HANDLE;
234 }
235
236 if( msg_obj == NULL )
237 {
238 LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
239 return eMSG_Q_INVALID_PARAMETER;
240 }
241
242 msg_q* p_msg_q = (msg_q*)msg_q_data;
243
244 pthread_mutex_lock(&p_msg_q->list_mutex);
245
246 if( p_msg_q->unblocked )
247 {
248 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
249 pthread_mutex_unlock(&p_msg_q->list_mutex);
250 return eMSG_Q_UNAVAILABLE_RESOURCE;
251 }
252
253 /* Wait for data in the message queue */
254 while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
255 {
256 pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
257 }
258
259 rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
260
261 pthread_mutex_unlock(&p_msg_q->list_mutex);
262
263 LOC_LOGV("%s: Received message %p rv = %d\n", __FUNCTION__, *msg_obj, rv);
264
265 return rv;
266 }
267
268 /*===========================================================================
269
270 FUNCTION: msg_q_flush
271
272 ===========================================================================*/
msg_q_flush(void * msg_q_data)273 msq_q_err_type msg_q_flush(void* msg_q_data)
274 {
275 msq_q_err_type rv;
276 if ( msg_q_data == NULL )
277 {
278 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
279 return eMSG_Q_INVALID_HANDLE;
280 }
281
282 msg_q* p_msg_q = (msg_q*)msg_q_data;
283
284 LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
285
286 pthread_mutex_lock(&p_msg_q->list_mutex);
287
288 /* Remove all elements from the list */
289 rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
290
291 pthread_mutex_unlock(&p_msg_q->list_mutex);
292
293 LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
294
295 return rv;
296 }
297
298 /*===========================================================================
299
300 FUNCTION: msg_q_unblock
301
302 ===========================================================================*/
msg_q_unblock(void * msg_q_data)303 msq_q_err_type msg_q_unblock(void* msg_q_data)
304 {
305 if ( msg_q_data == NULL )
306 {
307 LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
308 return eMSG_Q_INVALID_HANDLE;
309 }
310
311 msg_q* p_msg_q = (msg_q*)msg_q_data;
312 pthread_mutex_lock(&p_msg_q->list_mutex);
313
314 if( p_msg_q->unblocked )
315 {
316 LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
317 pthread_mutex_unlock(&p_msg_q->list_mutex);
318 return eMSG_Q_UNAVAILABLE_RESOURCE;
319 }
320
321 LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
322 /* Unblocking message queue */
323 p_msg_q->unblocked = 1;
324
325 /* Allow all the waiters to wake up */
326 pthread_cond_broadcast(&p_msg_q->list_cond);
327
328 pthread_mutex_unlock(&p_msg_q->list_mutex);
329
330 LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
331
332 return eMSG_Q_SUCCESS;
333 }
334