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, ¶m) < 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, ¶m) < 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