Remove unused include statement
[platform/core/multimedia/libmm-sound.git] / server / mm_sound_thread_pool.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26 #include <mm_error.h>
27 #include <mm_debug.h>
28 #include <mm_sound_thread_pool.h>
29
30 #define USE_G_THREAD_POOL
31 #ifdef USE_G_THREAD_POOL
32 #include <glib.h>
33 GThreadPool* g_pool;
34
35 #define MAX_UNUSED_THREADS_IN_THREADPOOL        10
36
37 typedef struct __THREAD_INFO
38 {
39         void (*func)(gpointer data);
40         void *param;
41 } THREAD_INFO;
42
43 static void __DummyWork (void* param)
44 {
45         debug_msg ("thread index = %d\n", (int)param);
46         sleep (1);
47 }
48
49 static void __ThreadWork(gpointer data, gpointer user_data)
50 {
51         THREAD_INFO* info = (THREAD_INFO*)data;
52         if (info) {
53                  if (info->func) {
54                                 debug_log ("Calling [%p] with param [%p]\n", info->func, info->param);
55                                 info->func (info->param);
56                  } else {
57                                 debug_warning ("No func to call....\n");
58                  }
59
60                  /* Info was allocated by MMSoundThreadPoolRun().
61                         The actual content of info should be  freed whether inside func or outside (if handle) */
62                  debug_log ("free [%p]\n", info);
63                  free (info);
64                  info = NULL;
65         } else {
66                 debug_warning ("No valid thread info...Nothing to do...\n");
67         }
68 }
69
70 int MMSoundThreadPoolDump(int fulldump)
71 {
72         if (g_pool == NULL) {
73                 debug_error ("No thread pool initialized....\n");
74                 return MM_ERROR_SOUND_INTERNAL;
75         }
76
77         if (fulldump) {
78                 debug_log ("##### [ThreadPool] max threads=[%d], max unused=[%d], max idle time=[%d]\n",
79                                 g_thread_pool_get_max_threads (g_pool),
80                                 g_thread_pool_get_max_unused_threads(),
81                                 g_thread_pool_get_max_idle_time()       );
82         }
83         debug_log ("***** [ThreadPool] running=[%d], unused=[%d]\n",
84                         g_thread_pool_get_num_threads (g_pool),
85                         g_thread_pool_get_num_unused_threads() );
86
87         return MM_ERROR_NONE;
88 }
89
90 int MMSoundThreadPoolInit()
91 {
92         int i=0;
93         GError* error = NULL;
94
95         /* Create thread pool (non-exclude mode with infinite max threads) */
96         g_pool = g_thread_pool_new (__ThreadWork, NULL, -1, FALSE, &error);
97         if (g_pool == NULL && error != NULL) {
98                 debug_error ("thread pool created failed : %s\n", error->message);
99                 g_error_free (error);
100                 return MM_ERROR_SOUND_INTERNAL;
101         }
102         debug_msg ("thread pool created successfully\n");
103
104         MMSoundThreadPoolDump(TRUE);
105
106         /* Thread pool setting : this will maintain at least 10 unused threads and this will be reused. */
107         /* If no unused thread left, new thread will be created, but always maintain 10 unused thread */
108         debug_msg ("thread pool set max unused threads to %d\n", MAX_UNUSED_THREADS_IN_THREADPOOL);
109         g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS_IN_THREADPOOL);
110
111         /* To reserve unused threads, let's start some threads for beggining
112            This dummy thread will be remained unused as soon as it started */
113         debug_msg ("run threads to reserve minimum thread\n");
114         for (i=0; i<MAX_UNUSED_THREADS_IN_THREADPOOL; i++) {
115                 MMSoundThreadPoolRun ((void *)i, __DummyWork);
116         }
117
118         MMSoundThreadPoolDump(TRUE);
119
120      return MM_ERROR_NONE;
121 }
122
123 int MMSoundThreadPoolRun(void *param, void (*func)(void*))
124 {
125         GError* error = NULL;
126
127         /* Dump current thread pool */
128         MMSoundThreadPoolDump(FALSE);
129
130         /* Create thread info structure.
131            This thread info data will be free in __ThreadWork(), after use. */
132         THREAD_INFO* thread_info = (THREAD_INFO*)malloc (sizeof(THREAD_INFO));
133         if (thread_info) {
134                 thread_info->func = func;
135                 thread_info->param = param;
136                 debug_log ("alloc thread_info = %p\n", thread_info);
137
138                 /* Add thread to queue of thread pool */
139                 g_thread_pool_push (g_pool, thread_info, &error);
140                 if (error) {
141                         debug_error ("g_thread_pool_push failed : %s\n", error->message);
142                         g_error_free (error);
143                         free(thread_info);
144                         return MM_ERROR_SOUND_INTERNAL;
145                 }
146         } else {
147                 debug_error("failed to alloc thread info\n");
148                 return MM_ERROR_SOUND_INTERNAL;
149         }
150
151         return MM_ERROR_NONE;
152 }
153
154 int MMSoundThreadPoolFini(void)
155 {
156         /* If immediate is TRUE, no new task is processed for pool.
157         Otherwise pool is not freed before the last task is processed.
158         Note however, that no thread of this pool is interrupted, while processing a task.
159         Instead at least all still running threads can finish their tasks before the pool is freed.
160
161         If wait_ is TRUE, the functions does not return before all tasks to be processed
162         (dependent on immediate, whether all or only the currently running) are ready.
163         Otherwise the function returns immediately.     */
164         debug_msg ("thread pool will be free\n");
165         g_thread_pool_free (g_pool, TRUE, FALSE);
166
167         return MM_ERROR_NONE;
168 }
169
170 #else // USE_G_THREAD_POOL
171
172 #define THREAD_POOL_MAX 10
173
174 struct __control_t
175 {
176         pthread_t threadid;
177         pthread_cond_t condition;
178         int stopflag;
179         void *param;
180         void (*func)(void *);
181 };
182
183 static int threadmap[THREAD_POOL_MAX];
184 static struct __control_t control[THREAD_POOL_MAX];
185
186 static pthread_cond_t startcond = PTHREAD_COND_INITIALIZER;
187 static pthread_mutex_t startsync = PTHREAD_MUTEX_INITIALIZER;
188 static pthread_mutex_t controlsync = PTHREAD_MUTEX_INITIALIZER;
189 static pthread_mutex_t funcsync = PTHREAD_MUTEX_INITIALIZER;
190
191 static int __GetEmptyPool(void)
192 {
193         int count = 0;
194         while ((count < THREAD_POOL_MAX) && threadmap[count] == 1)
195                 ++count;
196         return count == THREAD_POOL_MAX ? -1 : count;
197 }
198
199 static void __SetPool(int n)
200 {
201     threadmap[n] = 1;
202 }
203
204 static void __ResetPool(int n)
205 {
206     threadmap[n] = 0;
207 }
208
209 static void __InitPool(void)
210 {
211     int count = 0;
212     for (count = 0; count < THREAD_POOL_MAX; count++)
213     {
214         threadmap[count] = 0;
215         if (pthread_cond_init(&control[count].condition, NULL) != 0)
216             perror("Make Thread Condition");
217     }
218 }
219
220 static void __DestroyPool(void)
221 {
222     int count = 0;
223     for (count = 0; count < THREAD_POOL_MAX; count++)
224     {
225         if (pthread_cond_destroy(&control[count].condition) != 0)
226         {
227             perror("Remove Thread Condition");
228             exit(0);
229         }
230     }
231 }
232
233 static void* __ThreadWork(void *param)
234 {
235     int myid = -1;
236
237     myid = (int)param;
238
239     pthread_mutex_lock(&startsync);
240     pthread_cond_signal(&startcond);
241     pthread_mutex_unlock(&startsync);
242
243     while(1)
244     {
245         pthread_mutex_lock(&controlsync);
246         pthread_cond_wait(&control[myid].condition, &controlsync);
247         pthread_mutex_unlock(&controlsync);
248
249         if (control[myid].func != NULL)
250             control[myid].func(control[myid].param);
251 /*        if (control[myid].param != NULL)
252             free(control[myid].param);*/
253
254         control[myid].func = NULL;
255         control[myid].param = NULL;
256         pthread_mutex_lock(&startsync);
257         __ResetPool(myid);
258         pthread_mutex_unlock(&startsync);
259
260         if (control[myid].stopflag) {
261             pthread_exit(0);
262         }
263     }
264 }
265
266 int MMSoundThreadPoolDump(void)
267 {
268         int count = 0;
269         int ret = MM_ERROR_NONE;
270
271         fprintf(stdout, "================================================================================\n");
272         fprintf(stdout, "                              Thread States                                     \n");
273         fprintf(stdout, "--------------------------------------------------------------------------------\n");
274         for (count = 0; count < THREAD_POOL_MAX; count ++)
275         {
276                 fprintf(stdout, "Thread %d\n", control[count].threadid);
277                 fprintf(stdout, "Current State is \"%s\"\n", threadmap[count] ? "Running" : "Ready");
278                 if (threadmap[count])
279                 {
280                         fprintf(stdout, "Running function address %p\n", control[count].func);
281                 }
282                 else
283                 {
284                         fprintf(stdout, "Threadmap is NULL\n");
285                         ret = MM_ERROR_SOUND_INTERNAL;
286                 }
287         }
288         fprintf(stdout, "================================================================================\n");
289         return ret;
290 }
291
292 int MMSoundThreadPoolInit(void)
293 {
294     volatile int count = 0;
295     pthread_mutex_lock(&funcsync);
296
297     __InitPool();
298
299     for (count = 0; count < THREAD_POOL_MAX; count++)
300     {
301         control[count].stopflag = 0;
302         pthread_mutex_lock(&startsync);
303         if (pthread_create(&control[count].threadid, NULL, __ThreadWork, (void*)count) < 0)
304         {
305             perror("Make Thread Fail");
306             exit(0);
307         }
308         pthread_cond_wait(&startcond, &startsync);
309         pthread_mutex_unlock(&startsync);
310         usleep(100); /* Delay for thread init */
311     }
312     pthread_mutex_unlock(&funcsync);
313     return MM_ERROR_NONE;
314 }
315
316 int MMSoundThreadPoolRun(void *param, void (*func)(void*))
317 {
318     int poolnum = -1;
319
320     pthread_mutex_lock(&funcsync);
321     pthread_mutex_lock(&startsync);
322     poolnum = __GetEmptyPool();
323     if (poolnum < 0) {
324         pthread_mutex_unlock(&startsync);
325         pthread_mutex_unlock(&funcsync);
326         return MM_ERROR_COMMON_NO_FREE_SPACE;
327     }
328     __SetPool(poolnum);
329     pthread_mutex_unlock(&startsync);
330     control[poolnum].param = param;
331     control[poolnum].func = func;
332     pthread_cond_signal(&control[poolnum].condition);
333     pthread_mutex_unlock(&funcsync);
334
335     return MM_ERROR_NONE;
336 }
337
338 int MMSoundThreadPoolFini(void)
339 {
340     int count = 0;
341
342     pthread_mutex_lock(&funcsync);
343     for (count = 0; count < THREAD_POOL_MAX; count++)
344     {
345         control[count].stopflag = 1;
346         pthread_cond_signal(&control[count].condition);
347         if (pthread_join(control[count].threadid, NULL) < 0)
348         {
349             perror("Join Fail");
350             exit(0);
351         }
352     }
353     __DestroyPool();
354     pthread_mutex_unlock(&funcsync);
355
356     return MM_ERROR_NONE;
357 }
358 #endif // USE_G_THREAD_POOL
359