4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
28 #include <mm_sound_thread_pool.h>
30 #define USE_G_THREAD_POOL
31 #ifdef USE_G_THREAD_POOL
35 #define MAX_UNUSED_THREADS_IN_THREADPOOL 10
37 #define MIN_RUNNING_THREAD 0
39 typedef struct __THREAD_INFO
41 void (*func)(gpointer data);
45 static void __DummyWork (void* param)
47 debug_msg ("thread index = %d\n", (int)param);
51 static void __ThreadWork(gpointer data, gpointer user_data)
53 THREAD_INFO* info = (THREAD_INFO*)data;
56 debug_log ("Calling [%p] with param [%p]\n", info->func, info->param);
57 info->func (info->param);
59 debug_warning ("No func to call....\n");
62 /* Info was allocated by MMSoundThreadPoolRun().
63 The actual content of info should be freed whether inside func or outside (if handle) */
64 debug_log ("free [%p]\n", info);
68 debug_warning ("No valid thread info...Nothing to do...\n");
72 int MMSoundThreadPoolDump(int fulldump)
75 debug_error ("No thread pool initialized....\n");
76 return MM_ERROR_SOUND_INTERNAL;
80 debug_log ("##### [ThreadPool] max threads=[%d], max unused=[%d], max idle time=[%d]\n",
81 g_thread_pool_get_max_threads (g_pool),
82 g_thread_pool_get_max_unused_threads(),
83 g_thread_pool_get_max_idle_time() );
85 debug_log ("***** [ThreadPool] running=[%d], unused=[%d]\n",
86 g_thread_pool_get_num_threads (g_pool),
87 g_thread_pool_get_num_unused_threads() );
92 gboolean IsMMSoundThreadPoolRunning(void)
94 MMSoundThreadPoolDump(FALSE);
95 return (g_thread_pool_get_num_threads(g_pool) > MIN_RUNNING_THREAD);
98 int MMSoundThreadPoolInit()
101 GError* error = NULL;
103 /* Create thread pool (non-exclude mode with infinite max threads) */
104 g_pool = g_thread_pool_new (__ThreadWork, NULL, -1, FALSE, &error);
105 if (g_pool == NULL && error != NULL) {
106 debug_error ("thread pool created failed : %s\n", error->message);
107 g_error_free (error);
108 return MM_ERROR_SOUND_INTERNAL;
110 debug_msg ("thread pool created successfully\n");
112 MMSoundThreadPoolDump(TRUE);
114 /* Thread pool setting : this will maintain at least 10 unused threads and this will be reused. */
115 /* If no unused thread left, new thread will be created, but always maintain 10 unused thread */
116 debug_msg ("thread pool set max unused threads to %d\n", MAX_UNUSED_THREADS_IN_THREADPOOL);
117 g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS_IN_THREADPOOL);
119 /* To reserve unused threads, let's start some threads for beggining
120 This dummy thread will be remained unused as soon as it started */
121 debug_msg ("run threads to reserve minimum thread\n");
122 for (i=0; i<MAX_UNUSED_THREADS_IN_THREADPOOL; i++) {
123 MMSoundThreadPoolRun ((void *)i, __DummyWork);
126 MMSoundThreadPoolDump(TRUE);
128 return MM_ERROR_NONE;
131 int MMSoundThreadPoolRun(void *param, void (*func)(void*))
133 GError* error = NULL;
135 /* Dump current thread pool */
136 MMSoundThreadPoolDump(FALSE);
138 /* Create thread info structure.
139 This thread info data will be free in __ThreadWork(), after use. */
140 THREAD_INFO* thread_info = (THREAD_INFO*)malloc (sizeof(THREAD_INFO));
142 thread_info->func = func;
143 thread_info->param = param;
144 debug_log ("alloc thread_info = %p\n", thread_info);
146 /* Add thread to queue of thread pool */
147 g_thread_pool_push (g_pool, thread_info, &error);
149 debug_error ("g_thread_pool_push failed : %s\n", error->message);
150 g_error_free (error);
152 return MM_ERROR_SOUND_INTERNAL;
155 debug_error("failed to alloc thread info\n");
156 return MM_ERROR_SOUND_INTERNAL;
159 return MM_ERROR_NONE;
162 int MMSoundThreadPoolFini(void)
164 /* If immediate is TRUE, no new task is processed for pool.
165 Otherwise pool is not freed before the last task is processed.
166 Note however, that no thread of this pool is interrupted, while processing a task.
167 Instead at least all still running threads can finish their tasks before the pool is freed.
169 If wait_ is TRUE, the functions does not return before all tasks to be processed
170 (dependent on immediate, whether all or only the currently running) are ready.
171 Otherwise the function returns immediately. */
172 debug_msg ("thread pool will be free\n");
173 g_thread_pool_free (g_pool, TRUE, FALSE);
175 return MM_ERROR_NONE;
178 #else // USE_G_THREAD_POOL
180 #define THREAD_POOL_MAX 10
185 pthread_cond_t condition;
188 void (*func)(void *);
191 static int threadmap[THREAD_POOL_MAX];
192 static struct __control_t control[THREAD_POOL_MAX];
194 static pthread_cond_t startcond = PTHREAD_COND_INITIALIZER;
195 static pthread_mutex_t startsync = PTHREAD_MUTEX_INITIALIZER;
196 static pthread_mutex_t controlsync = PTHREAD_MUTEX_INITIALIZER;
197 static pthread_mutex_t funcsync = PTHREAD_MUTEX_INITIALIZER;
199 static int __GetEmptyPool(void)
202 while ((count < THREAD_POOL_MAX) && threadmap[count] == 1)
204 return count == THREAD_POOL_MAX ? -1 : count;
207 static void __SetPool(int n)
212 static void __ResetPool(int n)
217 static void __InitPool(void)
220 for (count = 0; count < THREAD_POOL_MAX; count++)
222 threadmap[count] = 0;
223 if (pthread_cond_init(&control[count].condition, NULL) != 0)
224 perror("Make Thread Condition");
228 static void __DestroyPool(void)
231 for (count = 0; count < THREAD_POOL_MAX; count++)
233 if (pthread_cond_destroy(&control[count].condition) != 0)
235 perror("Remove Thread Condition");
241 static void* __ThreadWork(void *param)
247 pthread_mutex_lock(&startsync);
248 pthread_cond_signal(&startcond);
249 pthread_mutex_unlock(&startsync);
253 pthread_mutex_lock(&controlsync);
254 pthread_cond_wait(&control[myid].condition, &controlsync);
255 pthread_mutex_unlock(&controlsync);
257 if (control[myid].func != NULL)
258 control[myid].func(control[myid].param);
259 /* if (control[myid].param != NULL)
260 free(control[myid].param);*/
262 control[myid].func = NULL;
263 control[myid].param = NULL;
264 pthread_mutex_lock(&startsync);
266 pthread_mutex_unlock(&startsync);
268 if (control[myid].stopflag) {
274 int MMSoundThreadPoolDump(void)
277 int ret = MM_ERROR_NONE;
279 fprintf(stdout, "================================================================================\n");
280 fprintf(stdout, " Thread States \n");
281 fprintf(stdout, "--------------------------------------------------------------------------------\n");
282 for (count = 0; count < THREAD_POOL_MAX; count ++)
284 fprintf(stdout, "Thread %d\n", control[count].threadid);
285 fprintf(stdout, "Current State is \"%s\"\n", threadmap[count] ? "Running" : "Ready");
286 if (threadmap[count])
288 fprintf(stdout, "Running function address %p\n", control[count].func);
292 fprintf(stdout, "Threadmap is NULL\n");
293 ret = MM_ERROR_SOUND_INTERNAL;
296 fprintf(stdout, "================================================================================\n");
300 int MMSoundThreadPoolInit(void)
302 volatile int count = 0;
303 pthread_mutex_lock(&funcsync);
307 for (count = 0; count < THREAD_POOL_MAX; count++)
309 control[count].stopflag = 0;
310 pthread_mutex_lock(&startsync);
311 if (pthread_create(&control[count].threadid, NULL, __ThreadWork, (void*)count) < 0)
313 perror("Make Thread Fail");
316 pthread_cond_wait(&startcond, &startsync);
317 pthread_mutex_unlock(&startsync);
318 usleep(100); /* Delay for thread init */
320 pthread_mutex_unlock(&funcsync);
321 return MM_ERROR_NONE;
324 int MMSoundThreadPoolRun(void *param, void (*func)(void*))
328 pthread_mutex_lock(&funcsync);
329 pthread_mutex_lock(&startsync);
330 poolnum = __GetEmptyPool();
332 pthread_mutex_unlock(&startsync);
333 pthread_mutex_unlock(&funcsync);
334 return MM_ERROR_COMMON_NO_FREE_SPACE;
337 pthread_mutex_unlock(&startsync);
338 control[poolnum].param = param;
339 control[poolnum].func = func;
340 pthread_cond_signal(&control[poolnum].condition);
341 pthread_mutex_unlock(&funcsync);
343 return MM_ERROR_NONE;
346 int MMSoundThreadPoolFini(void)
350 pthread_mutex_lock(&funcsync);
351 for (count = 0; count < THREAD_POOL_MAX; count++)
353 control[count].stopflag = 1;
354 pthread_cond_signal(&control[count].condition);
355 if (pthread_join(control[count].threadid, NULL) < 0)
362 pthread_mutex_unlock(&funcsync);
364 return MM_ERROR_NONE;
366 #endif // USE_G_THREAD_POOL