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 typedef struct __THREAD_INFO
39 void (*func)(gpointer data);
43 static void __DummyWork (void* param)
45 debug_msg ("thread index = %d\n", (int)param);
49 static void __ThreadWork(gpointer data, gpointer user_data)
51 THREAD_INFO* info = (THREAD_INFO*)data;
54 debug_log ("Calling [%p] with param [%p]\n", info->func, info->param);
55 info->func (info->param);
57 debug_warning ("No func to call....\n");
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);
66 debug_warning ("No valid thread info...Nothing to do...\n");
70 int MMSoundThreadPoolDump(int fulldump)
73 debug_error ("No thread pool initialized....\n");
74 return MM_ERROR_SOUND_INTERNAL;
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() );
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() );
90 int MMSoundThreadPoolInit()
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);
100 return MM_ERROR_SOUND_INTERNAL;
102 debug_msg ("thread pool created successfully\n");
104 MMSoundThreadPoolDump(TRUE);
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);
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);
118 MMSoundThreadPoolDump(TRUE);
120 return MM_ERROR_NONE;
123 int MMSoundThreadPoolRun(void *param, void (*func)(void*))
125 GError* error = NULL;
127 /* Dump current thread pool */
128 MMSoundThreadPoolDump(FALSE);
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));
134 thread_info->func = func;
135 thread_info->param = param;
136 debug_log ("alloc thread_info = %p\n", thread_info);
138 /* Add thread to queue of thread pool */
139 g_thread_pool_push (g_pool, thread_info, &error);
141 debug_error ("g_thread_pool_push failed : %s\n", error->message);
142 g_error_free (error);
144 return MM_ERROR_SOUND_INTERNAL;
147 debug_error("failed to alloc thread info\n");
148 return MM_ERROR_SOUND_INTERNAL;
151 return MM_ERROR_NONE;
154 int MMSoundThreadPoolFini(void)
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.
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);
167 return MM_ERROR_NONE;
170 #else // USE_G_THREAD_POOL
172 #define THREAD_POOL_MAX 10
177 pthread_cond_t condition;
180 void (*func)(void *);
183 static int threadmap[THREAD_POOL_MAX];
184 static struct __control_t control[THREAD_POOL_MAX];
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;
191 static int __GetEmptyPool(void)
194 while ((count < THREAD_POOL_MAX) && threadmap[count] == 1)
196 return count == THREAD_POOL_MAX ? -1 : count;
199 static void __SetPool(int n)
204 static void __ResetPool(int n)
209 static void __InitPool(void)
212 for (count = 0; count < THREAD_POOL_MAX; count++)
214 threadmap[count] = 0;
215 if (pthread_cond_init(&control[count].condition, NULL) != 0)
216 perror("Make Thread Condition");
220 static void __DestroyPool(void)
223 for (count = 0; count < THREAD_POOL_MAX; count++)
225 if (pthread_cond_destroy(&control[count].condition) != 0)
227 perror("Remove Thread Condition");
233 static void* __ThreadWork(void *param)
239 pthread_mutex_lock(&startsync);
240 pthread_cond_signal(&startcond);
241 pthread_mutex_unlock(&startsync);
245 pthread_mutex_lock(&controlsync);
246 pthread_cond_wait(&control[myid].condition, &controlsync);
247 pthread_mutex_unlock(&controlsync);
249 if (control[myid].func != NULL)
250 control[myid].func(control[myid].param);
251 /* if (control[myid].param != NULL)
252 free(control[myid].param);*/
254 control[myid].func = NULL;
255 control[myid].param = NULL;
256 pthread_mutex_lock(&startsync);
258 pthread_mutex_unlock(&startsync);
260 if (control[myid].stopflag) {
266 int MMSoundThreadPoolDump(void)
269 int ret = MM_ERROR_NONE;
271 fprintf(stdout, "================================================================================\n");
272 fprintf(stdout, " Thread States \n");
273 fprintf(stdout, "--------------------------------------------------------------------------------\n");
274 for (count = 0; count < THREAD_POOL_MAX; count ++)
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])
280 fprintf(stdout, "Running function address %p\n", control[count].func);
284 fprintf(stdout, "Threadmap is NULL\n");
285 ret = MM_ERROR_SOUND_INTERNAL;
288 fprintf(stdout, "================================================================================\n");
292 int MMSoundThreadPoolInit(void)
294 volatile int count = 0;
295 pthread_mutex_lock(&funcsync);
299 for (count = 0; count < THREAD_POOL_MAX; count++)
301 control[count].stopflag = 0;
302 pthread_mutex_lock(&startsync);
303 if (pthread_create(&control[count].threadid, NULL, __ThreadWork, (void*)count) < 0)
305 perror("Make Thread Fail");
308 pthread_cond_wait(&startcond, &startsync);
309 pthread_mutex_unlock(&startsync);
310 usleep(100); /* Delay for thread init */
312 pthread_mutex_unlock(&funcsync);
313 return MM_ERROR_NONE;
316 int MMSoundThreadPoolRun(void *param, void (*func)(void*))
320 pthread_mutex_lock(&funcsync);
321 pthread_mutex_lock(&startsync);
322 poolnum = __GetEmptyPool();
324 pthread_mutex_unlock(&startsync);
325 pthread_mutex_unlock(&funcsync);
326 return MM_ERROR_COMMON_NO_FREE_SPACE;
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);
335 return MM_ERROR_NONE;
338 int MMSoundThreadPoolFini(void)
342 pthread_mutex_lock(&funcsync);
343 for (count = 0; count < THREAD_POOL_MAX; count++)
345 control[count].stopflag = 1;
346 pthread_cond_signal(&control[count].condition);
347 if (pthread_join(control[count].threadid, NULL) < 0)
354 pthread_mutex_unlock(&funcsync);
356 return MM_ERROR_NONE;
358 #endif // USE_G_THREAD_POOL