Replace glib threadpool usage with a 'dumb' thread implementation.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / common / src / cathreadpool_pthreads.c
1 /* ****************************************************************
2  *
3  * Copyright 2014 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  ******************************************************************/
20
21 /**
22  * @file
23  *
24  * This file provides APIs related to thread pool.
25  */
26
27 #include <pthread.h>
28 #include "cathreadpool.h"
29 #include "logger.h"
30 #include "oic_malloc.h"
31
32 #define TAG PCF("UTHREADPOOL")
33
34 /**
35  * empty struct to represent the details.  This implementation has no data
36  * that it needs to keep track of, so it only uses NULL for the internal value.
37  */
38 typedef struct ca_thread_pool_details_t
39 {
40 } ca_thread_pool_details_t;
41
42 /**
43  * struct to wrap the pthreads callback properly.  The function pointer for
44  * pthreads requires a void* return value, however u_thread_func is a void.
45  */
46 typedef struct ca_thread_pool_callback_info_t
47 {
48     ca_thread_func func;
49     void* data;
50 } ca_thread_pool_callback_info_t;
51
52 // passthrough function to convert the pthreads call to a u_thread_func call
53 void* ca_thread_pool_pthreads_delegate(void* data)
54 {
55     ca_thread_pool_callback_info_t* info = (ca_thread_pool_callback_info_t*)data;
56     info->func(info->data);
57     OICFree(info);
58     return NULL;
59 }
60
61 // this implementation doesn't do a thread pool, so this function is essentially
62 // a no-op besides creating a valid ca_thread_pool_t object.  It was determined after
63 // reading through the existing implementation that the thread-pooling was unnecessary
64 // for the posix platforms.  Behavior shouldn't be changed since previously num_of_threads
65 // was greater than the number of requested threads.
66 CAResult_t ca_thread_pool_init(int32_t num_of_threads, ca_thread_pool_t *thread_pool)
67 {
68     OIC_LOG(DEBUG, TAG, "IN");
69
70     if(!thread_pool)
71     {
72         OIC_LOG(ERROR, TAG, "Parameter thraed_pool was null!");
73         return CA_STATUS_INVALID_PARAM;
74     }
75
76     if(num_of_threads <= 0)
77     {
78         OIC_LOG(ERROR, TAG, "num_of_threads must be positive and non-zero");
79         return CA_STATUS_INVALID_PARAM;
80     }
81
82     *thread_pool = OICMalloc(sizeof(struct ca_thread_pool));
83
84     if(!*thread_pool)
85     {
86         OIC_LOG(ERROR, TAG, "Failed to allocate for thread-pool");
87         return CA_MEMORY_ALLOC_FAILED;
88     }
89
90     OIC_LOG(DEBUG, TAG, "OUT");
91     return CA_STATUS_OK;
92 }
93
94 CAResult_t ca_thread_pool_add_task(ca_thread_pool_t thread_pool, ca_thread_func method,
95                                     void *data)
96 {
97     OIC_LOG(DEBUG, TAG, "IN");
98
99     if(NULL == thread_pool || NULL == method)
100     {
101         OIC_LOG(ERROR, TAG, "thread_pool or method was NULL");
102         return CA_STATUS_INVALID_PARAM;
103     }
104
105     ca_thread_pool_callback_info_t* info = OICMalloc(sizeof(ca_thread_pool_callback_info_t));
106     if(!info)
107     {
108         OIC_LOG(ERROR, TAG, "Failed to allocate for memory wrapper");
109         return CA_MEMORY_ALLOC_FAILED;
110     }
111
112     info->func = method;
113     info->data = data;
114
115     pthread_t threadHandle;
116
117     int result = pthread_create(&threadHandle, NULL, ca_thread_pool_pthreads_delegate, info);
118
119     if(result != 0)
120     {
121         OIC_LOG_V(ERROR, TAG, "Thread start failed with error %d", result);
122         return CA_STATUS_FAILED;
123     }
124
125     // detach will cause the thread to either terminate normally and clean up after
126     // itself, which prevents us from having to do any manual join/cleanup later, or
127     // it will be terminated upon application exit.
128     result = pthread_detach(threadHandle);
129
130     if(result != 0)
131     {
132         OIC_LOG_V(ERROR, TAG, "Thread detach failed with error %d", result);
133         return CA_STATUS_FAILED;
134     }
135
136     OIC_LOG(DEBUG, TAG, "OUT");
137     return CA_STATUS_OK;
138 }
139
140 void ca_thread_pool_free(ca_thread_pool_t thread_pool)
141 {
142     OIC_LOG(DEBUG, TAG, "IN");
143
144     OICFree(thread_pool);
145     OIC_LOG(DEBUG, TAG, "OUT");
146 }