1 /*
2     KHOMP generic endpoint/channel library.
3     Copyright (C) 2007-2009 Khomp Ind. & Com.
4 
5   The contents of this file are subject to the Mozilla Public License Version 1.1
6   (the "License"); you may not use this file except in compliance with the
7   License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
8 
9   Software distributed under the License is distributed on an "AS IS" basis,
10   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
11   the specific language governing rights and limitations under the License.
12 
13   Alternatively, the contents of this file may be used under the terms of the
14   "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
15   case the provisions of "LGPL License" are applicable instead of those above.
16 
17   If you wish to allow use of your version of this file only under the terms of
18   the LGPL License and not to allow others to use your version of this file under
19   the MPL, indicate your decision by deleting the provisions above and replace them
20   with the notice and other provisions required by the LGPL License. If you do not
21   delete the provisions above, a recipient may use your version of this file under
22   either the MPL or the LGPL License.
23 
24   The LGPL header follows below:
25 
26     This library is free software; you can redistribute it and/or
27     modify it under the terms of the GNU Lesser General Public
28     License as published by the Free Software Foundation; either
29     version 2.1 of the License, or (at your option) any later version.
30 
31     This library is distributed in the hope that it will be useful,
32     but WITHOUT ANY WARRANTY; without even the implied warranty of
33     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
34     Lesser General Public License for more details.
35 
36     You should have received a copy of the GNU Lesser General Public License
37     along with this library; if not, write to the Free Software Foundation, Inc.,
38     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
39 
40 */
41 
42 #ifndef _THREAD_HPP_
43 #define _THREAD_HPP_
44 
45 #include <thread.hpp>
46 
47 extern "C"
48 {
49     #include <switch.h>
50 }
51 
52 struct Thread : ThreadCommon
53 {
54     typedef switch_thread_t BaseThreadType;
55 
56     template<typename T, typename R, typename A>
57     struct ThreadData : ThreadDataCommon
58     {
ThreadDataThread::ThreadData59         ThreadData(T data, A arg) : _data(data), _arg(arg) {}
60 
runThread::ThreadData61         int run()
62         {
63             return _data(_arg);
64         }
65 
66         T _data;
67         A _arg;
68     };
69 
70     template<typename T, typename R>
71     struct ThreadData < T, R, void > : ThreadDataCommon
72     {
ThreadDataThread::ThreadData73         ThreadData(T data) : _data(data) {}
74 
runThread::ThreadData75         int run()
76         {
77             return _data();
78         }
79 
80         T _data;
81     };
82 
83     template<typename T, typename A>
84     struct ThreadData < T, void, A > : ThreadDataCommon
85     {
ThreadDataThread::ThreadData86         ThreadData(T data, A arg) : _data(data), _arg(arg) {}
87 
runThread::ThreadData88         int run()
89         {
90             _data(_arg);
91             return 0;
92         }
93 
94         T _data;
95         A _arg;
96     };
97 
98 
99     template<typename T>
100     struct ThreadData < T, void, void > : ThreadDataCommon
101     {
ThreadDataThread::ThreadData102         ThreadData(T data) : _data(data) {}
103 
runThread::ThreadData104         int run()
105         {
106             _data();
107             return 0;
108         }
109 
110         T _data;
111     };
112 
113     template<typename T>
ThreadThread114     Thread(T obj, switch_memory_pool_t *pool=NULL) :
115             _thread_info(new ThreadData<T, typename DecomposeFunction<T>::Return, void>(obj)),
116             _pool(pool),
117             _can_delete_pool(false)
118     {
119         if(!_pool)
120         {
121             switch_core_new_memory_pool(&_pool);
122             _can_delete_pool = true;
123         }
124 
125         _thread_info->_thread = this;
126         _thread_info->_self = NULL;
127         _thread_info->_attribute = NULL;
128 
129         if(switch_threadattr_create(
130                 (switch_threadattr_t **)&_thread_info->_attribute, _pool) != 0)
131         {
132             _thread_info->_attribute = NULL;
133             return;
134         }
135 
136         switch_threadattr_stacksize_set(
137                 (switch_threadattr_t *)_thread_info->_attribute,
138                 SWITCH_THREAD_STACKSIZE);
139 
140         if(!priority())
141         {
142             _thread_info->_attribute = NULL;
143         }
144 
145     }
146 
147     template<typename T, typename A>
ThreadThread148     Thread(T obj, A arg, switch_memory_pool_t *pool=NULL) :
149             _thread_info(new ThreadData<T, typename DecomposeFunction<T>::Return, A>(obj, arg)),
150             _pool(pool),
151             _can_delete_pool(false)
152     {
153         if(!_pool)
154         {
155             switch_core_new_memory_pool(&_pool);
156             _can_delete_pool = true;
157         }
158 
159         _thread_info->_thread = this;
160         _thread_info->_self = NULL;
161         _thread_info->_attribute = NULL;
162 
163         if(switch_threadattr_create(
164                 (switch_threadattr_t **)&_thread_info->_attribute, _pool) != 0)
165         {
166             _thread_info->_attribute = NULL;
167             return;
168         }
169 
170         switch_threadattr_stacksize_set(
171                 (switch_threadattr_t *)_thread_info->_attribute,
172                 SWITCH_THREAD_STACKSIZE);
173 
174         if(!priority())
175         {
176             _thread_info->_attribute = NULL;
177         }
178 
179     }
180 
~ThreadThread181     ~Thread()
182     {
183         if(_thread_info)
184             delete _thread_info;
185 
186         if (_can_delete_pool)
187             switch_core_destroy_memory_pool(&_pool);
188     }
189 
detachThread190     void detach(bool d = true)
191     {
192         if(!_thread_info->_attribute)
193             return;
194 
195         /* Non-zero if detached threads should be created. */
196         switch_threadattr_detach_set(
197                 (switch_threadattr_t *)_thread_info->_attribute, d ? 1 : 0);
198     }
199 
startThread200     bool start()
201     {
202         if(!_pool || !_thread_info->_attribute)
203             return false;
204 
205         switch_thread_create((switch_thread_t**)&_thread_info->_self,
206                 (switch_threadattr_t *)_thread_info->_attribute,
207                 run,
208                 _thread_info,
209                 _pool);
210 
211         if(!_thread_info->_self)
212             return false;
213 
214         return true;
215     }
216 
joinThread217     int join()
218     {
219         /*
220          * block until the desired thread stops executing.
221          * @param retval The return value from the dead thread.
222          * @param thd The thread to join
223          *
224          * SWITCH_DECLARE(switch_status_t) switch_thread_join(switch_status_t *retval, switch_thread_t *thd);
225         */
226 
227         if(!_thread_info->_self)
228             return -2;
229 
230         int retval = 0;
231 
232         if(switch_thread_join((switch_status_t*)&retval,
233                 (switch_thread_t *)_thread_info->_self) != 0)
234             return -1;
235 
236         return retval;
237     }
238 
selfThread239     BaseThreadType * self()
240     {
241         //switch_thread_self();
242         //apr_os_thread_current();
243         return (BaseThreadType *)_thread_info->_self;
244     }
245 
246 private:
exitThread247     void exit(int status)
248     {
249         /**
250          * stop the current thread
251          * @param thd The thread to stop
252          * @param retval The return value to pass back to any thread that cares
253          */
254         //SWITCH_DECLARE(switch_status_t) switch_thread_exit(switch_thread_t *thd, switch_status_t retval);
255         switch_thread_exit((switch_thread_t *)_thread_info->_self, (switch_status_t)status);
256 
257     }
258 
259 #ifndef WIN32
260     struct apr_threadattr_t {
261         apr_pool_t *pool;
262         pthread_attr_t attr;
263     };
264 #endif
265 
priorityThread266     bool priority()
267     {
268 #ifndef WIN32
269         struct sched_param param;
270 
271         struct apr_threadattr_t *myattr = (struct apr_threadattr_t *)_thread_info->_attribute;
272 
273         if (pthread_attr_setschedpolicy(
274                 (pthread_attr_t *)&myattr->attr, SCHED_RR) < 0)
275             return false;
276 
277         if (pthread_attr_getschedparam(
278                 (pthread_attr_t *)&myattr->attr, &param) < 0)
279             return false;
280 
281         param.sched_priority = sched_get_priority_max(SCHED_RR);
282 
283         if (pthread_attr_setschedparam(
284                 (pthread_attr_t *)&myattr->attr, &param) < 0)
285             return false;
286 
287 #endif
288         return true;
289 
290 /*
291         //BUG in Freeswitch
292 
293 THANKS FOR NOT REPORTING IT SO WE MUST LIVE WITH A PROBLEM YOU KNOW ABOUT .....
294 
295         if(switch_threadattr_priority_increase(
296                 (switch_threadattr_t *)_thread_info->_attribute) != 0)
297             return false;
298 
299         return true;
300 */
301     }
302 
303 
304 protected:
305     ThreadDataCommon * _thread_info;
306     switch_memory_pool_t *_pool;
307     bool _can_delete_pool;
308 
309 protected:
310 
runThread311     static void *SWITCH_THREAD_FUNC run(BaseThreadType *thread, void * obj)
312     {
313         //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
314         //        "Starting new Thread\n");
315 
316         ThreadDataCommon * data = (ThreadDataCommon *)obj;
317         int retval = data->run();
318 
319         //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
320         //        "Stopping new Thread = %d\n", retval);
321 
322         ((Thread *)(data->_thread))->exit(retval);
323 
324         return NULL;
325     }
326 
327 };
328 
329 
330 #endif /* _THREAD_HPP_ */
331