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.
31 #if defined HAVE_PTHREAD_H
34 #if defined HAVE_WINSOCK2_H
37 #include "cathreadpool.h"
39 #include "oic_malloc.h"
40 #include "uarraylist.h"
42 #include "platform_features.h"
44 #define TAG PCF("UTHREADPOOL")
47 * empty struct to represent the details. This implementation has no data
48 * that it needs to keep track of, so it only uses NULL for the internal value.
50 typedef struct ca_thread_pool_details_t
52 u_arraylist_t* threads_list;
54 } ca_thread_pool_details_t;
57 * struct to wrap the pthreads callback properly. The function pointer for
58 * pthreads requires a void* return value, however u_thread_func is a void.
60 typedef struct ca_thread_pool_callback_info_t
64 } ca_thread_pool_callback_info_t;
66 // passthrough function to convert the pthreads call to a u_thread_func call
67 void* ca_thread_pool_pthreads_delegate(void* data)
69 ca_thread_pool_callback_info_t* info = (ca_thread_pool_callback_info_t*)data;
70 info->func(info->data);
75 // this implementation doesn't do a thread pool, so this function is essentially
76 // a no-op besides creating a valid ca_thread_pool_t object. It was determined after
77 // reading through the existing implementation that the thread-pooling was unnecessary
78 // for the posix platforms. Behavior shouldn't be changed since previously num_of_threads
79 // was greater than the number of requested threads.
80 CAResult_t ca_thread_pool_init(int32_t num_of_threads, ca_thread_pool_t *thread_pool)
82 OIC_LOG(DEBUG, TAG, "IN");
86 OIC_LOG(ERROR, TAG, "Parameter thread_pool was null!");
87 return CA_STATUS_INVALID_PARAM;
90 if(num_of_threads <= 0)
92 OIC_LOG(ERROR, TAG, "num_of_threads must be positive and non-zero");
93 return CA_STATUS_INVALID_PARAM;
96 *thread_pool = OICMalloc(sizeof(struct ca_thread_pool));
100 OIC_LOG(ERROR, TAG, "Failed to allocate for thread-pool");
101 return CA_MEMORY_ALLOC_FAILED;
104 (*thread_pool)->details = OICMalloc(sizeof(struct ca_thread_pool_details_t));
105 if(!(*thread_pool)->details)
107 OIC_LOG(ERROR, TAG, "Failed to allocate for thread-pool details");
108 OICFree(*thread_pool);
110 return CA_MEMORY_ALLOC_FAILED;
113 (*thread_pool)->details->list_lock = ca_mutex_new();
115 if(!(*thread_pool)->details->list_lock)
117 OIC_LOG(ERROR, TAG, "Failed to create thread-pool mutex");
121 (*thread_pool)->details->threads_list = u_arraylist_create();
123 if(!(*thread_pool)->details->threads_list)
125 OIC_LOG(ERROR, TAG, "Failed to create thread-pool list");
126 if(!ca_mutex_free((*thread_pool)->details->list_lock))
128 OIC_LOG(ERROR, TAG, "Failed to free thread-pool mutex");
133 OIC_LOG(DEBUG, TAG, "OUT");
137 OICFree((*thread_pool)->details);
138 OICFree(*thread_pool);
140 return CA_STATUS_FAILED;
143 CAResult_t ca_thread_pool_add_task(ca_thread_pool_t thread_pool, ca_thread_func method,
146 OIC_LOG(DEBUG, TAG, "IN");
148 if(NULL == thread_pool || NULL == method)
150 OIC_LOG(ERROR, TAG, "thread_pool or method was NULL");
151 return CA_STATUS_INVALID_PARAM;
154 ca_thread_pool_callback_info_t* info = OICMalloc(sizeof(ca_thread_pool_callback_info_t));
157 OIC_LOG(ERROR, TAG, "Failed to allocate for memory wrapper");
158 return CA_MEMORY_ALLOC_FAILED;
164 pthread_t threadHandle;
165 int result = pthread_create(&threadHandle, NULL, ca_thread_pool_pthreads_delegate, info);
169 OIC_LOG_V(ERROR, TAG, "Thread start failed with error %d", result);
170 return CA_STATUS_FAILED;
173 ca_mutex_lock(thread_pool->details->list_lock);
174 bool addResult = u_arraylist_add(thread_pool->details->threads_list, (void*)threadHandle);
175 ca_mutex_unlock(thread_pool->details->list_lock);
179 OIC_LOG_V(ERROR, TAG, "Arraylist Add failed, may not be properly joined: %d", addResult);
180 return CA_STATUS_FAILED;
183 OIC_LOG(DEBUG, TAG, "OUT");
187 void ca_thread_pool_free(ca_thread_pool_t thread_pool)
189 OIC_LOG(DEBUG, TAG, "IN");
193 OIC_LOG(ERROR, TAG, "Invalid parameter thread_pool was NULL");
197 ca_mutex_lock(thread_pool->details->list_lock);
199 for(uint32_t i = 0; i<u_arraylist_length(thread_pool->details->threads_list); ++i)
201 pthread_t tid = (pthread_t)u_arraylist_get(thread_pool->details->threads_list, i);
203 DWORD joinres = WaitForSingleObject(tid, INFINITE);
204 if (WAIT_OBJECT_0 != joinres)
206 OIC_LOG_V(ERROR, TAG, "Failed to join thread at index %u with error %d", i, joinres);
210 int joinres = pthread_join(tid, NULL);
213 OIC_LOG_V(ERROR, TAG, "Failed to join thread at index %u with error %d", i, joinres);
218 u_arraylist_free(&(thread_pool->details->threads_list));
220 ca_mutex_unlock(thread_pool->details->list_lock);
221 ca_mutex_free(thread_pool->details->list_lock);
223 OICFree(thread_pool->details);
224 OICFree(thread_pool);
226 OIC_LOG(DEBUG, TAG, "OUT");