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
39typedef 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/*===========================================================================
47FUNCTION    convert_linked_list_err_type
48
49DESCRIPTION
50   Converts from one set of enum values to another.
51
52   linked_list_val: Value to convert to msg_q_enum_type
53
54DEPENDENCIES
55   N/A
56
57RETURN VALUE
58   Corresponding linked_list_enum_type in msg_q_enum_type
59
60SIDE EFFECTS
61   N/A
62
63===========================================================================*/
64static 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  ===========================================================================*/
92msq_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  ===========================================================================*/
144msq_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  ===========================================================================*/
171msq_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  ===========================================================================*/
214msq_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  ===========================================================================*/
262msq_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  ===========================================================================*/
292msq_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