1 /* ****************************************************************
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 ******************************************************************/
24 * This file provides APIs related to thread pool.
30 #include "iotivity_config.h"
32 #if defined HAVE_WINSOCK2_H
35 #include "cathreadpool.h"
37 #include "oic_malloc.h"
38 #include "uarraylist.h"
41 #include "platform_features.h"
43 #define TAG PCF("UTHREADPOOL")
46 * empty struct to represent the details. This implementation has no data
47 * that it needs to keep track of, so it only uses NULL for the internal value.
49 typedef struct ca_thread_pool_details_t
51 u_arraylist_t* threads_list;
53 } ca_thread_pool_details_t;
56 * struct to wrap the pthreads callback properly. The function pointer for
57 * pthreads requires a void* return value, however u_thread_func is a void.
59 typedef struct ca_thread_pool_callback_info_t
63 } ca_thread_pool_callback_info_t;
65 typedef struct ca_thread_pool_thread_info_t
69 } ca_thread_pool_thread_info_t;
71 // passthrough function to convert the pthreads call to a u_thread_func call
72 void* ca_thread_pool_pthreads_delegate(void* data)
74 ca_thread_pool_callback_info_t* info = (ca_thread_pool_callback_info_t*)data;
75 info->func(info->data);
80 // this implementation doesn't do a thread pool, so this function is essentially
81 // a no-op besides creating a valid ca_thread_pool_t object. It was determined after
82 // reading through the existing implementation that the thread-pooling was unnecessary
83 // for the posix platforms. Behavior shouldn't be changed since previously num_of_threads
84 // was greater than the number of requested threads.
85 CAResult_t ca_thread_pool_init(int32_t num_of_threads, ca_thread_pool_t *thread_pool)
87 OIC_LOG(DEBUG, TAG, "IN");
91 OIC_LOG(ERROR, TAG, "Parameter thread_pool was null!");
92 return CA_STATUS_INVALID_PARAM;
95 if(num_of_threads <= 0)
97 OIC_LOG(ERROR, TAG, "num_of_threads must be positive and non-zero");
98 return CA_STATUS_INVALID_PARAM;
101 *thread_pool = OICMalloc(sizeof(struct ca_thread_pool));
105 OIC_LOG(ERROR, TAG, "Failed to allocate for thread-pool");
106 return CA_MEMORY_ALLOC_FAILED;
109 (*thread_pool)->details = OICMalloc(sizeof(struct ca_thread_pool_details_t));
110 if(!(*thread_pool)->details)
112 OIC_LOG(ERROR, TAG, "Failed to allocate for thread-pool details");
113 OICFree(*thread_pool);
115 return CA_MEMORY_ALLOC_FAILED;
118 (*thread_pool)->details->list_lock = oc_mutex_new();
120 if(!(*thread_pool)->details->list_lock)
122 OIC_LOG(ERROR, TAG, "Failed to create thread-pool mutex");
126 (*thread_pool)->details->threads_list = u_arraylist_create();
128 if(!(*thread_pool)->details->threads_list)
130 OIC_LOG(ERROR, TAG, "Failed to create thread-pool list");
131 if(!oc_mutex_free((*thread_pool)->details->list_lock))
133 OIC_LOG(ERROR, TAG, "Failed to free thread-pool mutex");
138 OIC_LOG(DEBUG, TAG, "OUT");
142 OICFree((*thread_pool)->details);
143 OICFree(*thread_pool);
145 return CA_STATUS_FAILED;
149 CAResult_t ca_thread_pool_add_task(ca_thread_pool_t thread_pool, ca_thread_func method, void *data,
152 CAResult_t ca_thread_pool_add_task(ca_thread_pool_t thread_pool, ca_thread_func method, void *data,
153 uint32_t *taskId, const char *task_name, int stack_size)
156 OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
158 if(NULL == thread_pool || NULL == method)
160 OIC_LOG(ERROR, TAG, "thread_pool or method was NULL");
161 return CA_STATUS_INVALID_PARAM;
164 ca_thread_pool_callback_info_t* info = OICMalloc(sizeof(ca_thread_pool_callback_info_t));
167 OIC_LOG(ERROR, TAG, "Failed to allocate for memory wrapper");
168 return CA_MEMORY_ALLOC_FAILED;
174 ca_thread_pool_thread_info_t *threadInfo =
175 (ca_thread_pool_thread_info_t *) OICCalloc(1, sizeof(ca_thread_pool_thread_info_t));
178 OIC_LOG(ERROR, TAG, "Memory allocation failed");
180 return CA_STATUS_FAILED;
182 threadInfo->taskId = OCGetRandom();
185 *taskId = threadInfo->taskId;
188 oc_mutex_lock(thread_pool->details->list_lock);
189 bool addResult = u_arraylist_add(thread_pool->details->threads_list, (void*) threadInfo);
192 // Note that this is considered non-fatal.
193 oc_mutex_unlock(thread_pool->details->list_lock);
194 OIC_LOG(ERROR, TAG, "Arraylist add failed");
197 return CA_STATUS_FAILED;
201 int thrRet = oc_thread_new(&threadInfo->thread, ca_thread_pool_pthreads_delegate, info);
203 int thrRet = oc_thread_new(&threadInfo->thread, ca_thread_pool_pthreads_delegate, info,
204 task_name, stack_size);
209 if (u_arraylist_get_index(thread_pool->details->threads_list, threadInfo, &index))
211 u_arraylist_remove(thread_pool->details->threads_list, index);
213 oc_mutex_unlock(thread_pool->details->list_lock);
214 OIC_LOG_V(ERROR, TAG, "Thread start failed with error %d", thrRet);
216 return CA_STATUS_FAILED;
218 OIC_LOG_V(DEBUG, TAG, "created taskId: %u", threadInfo->taskId);
219 oc_mutex_unlock(thread_pool->details->list_lock);
221 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
225 CAResult_t ca_thread_pool_remove_task(ca_thread_pool_t thread_pool, uint32_t taskId)
227 OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
231 OIC_LOG(ERROR, TAG, "Invalid parameter thread_pool was NULL");
232 return CA_STATUS_FAILED;
235 oc_mutex_lock(thread_pool->details->list_lock);
236 for (uint32_t i = 0; i < u_arraylist_length(thread_pool->details->threads_list); ++i)
238 ca_thread_pool_thread_info_t *threadInfo = (ca_thread_pool_thread_info_t *)
239 u_arraylist_get(thread_pool->details->threads_list, i);
242 if (threadInfo->taskId == taskId)
244 OIC_LOG_V(INFO, TAG, "waiting.. taskId: %u", threadInfo->taskId);
245 oc_thread_wait(threadInfo->thread);
247 OIC_LOG_V(DEBUG, TAG, "removed taskId: %u", threadInfo->taskId);
248 u_arraylist_remove(thread_pool->details->threads_list, i);
249 oc_thread_free(threadInfo->thread);
255 oc_mutex_unlock(thread_pool->details->list_lock);
257 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
261 void ca_thread_pool_free(ca_thread_pool_t thread_pool)
263 OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
267 OIC_LOG(ERROR, TAG, "Invalid parameter thread_pool was NULL");
271 oc_mutex_lock(thread_pool->details->list_lock);
273 for (uint32_t i = 0; i < u_arraylist_length(thread_pool->details->threads_list); ++i)
275 ca_thread_pool_thread_info_t *threadInfo = (ca_thread_pool_thread_info_t *)
276 u_arraylist_get(thread_pool->details->threads_list, i);
279 if (threadInfo->thread)
282 OIC_LOG_V(INFO, TAG, "canceling.. thread: %p", threadInfo->thread);
283 oc_thread_cancel(threadInfo->thread);
285 OIC_LOG_V(INFO, TAG, "waiting.. thread: %p", threadInfo->thread);
286 oc_thread_wait(threadInfo->thread);
287 oc_thread_free(threadInfo->thread);
293 u_arraylist_free(&(thread_pool->details->threads_list));
295 oc_mutex_unlock(thread_pool->details->list_lock);
296 oc_mutex_free(thread_pool->details->list_lock);
298 OICFree(thread_pool->details);
299 OICFree(thread_pool);
301 OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);