• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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