00001 // ----------------------------------------------------------------------^ 00002 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Giorgio Calderone 00003 // (mailto: <gcalderone@ifc.inaf.it>) 00004 // 00005 // This file is part of MCS. 00006 // 00007 // MCS is free software; you can redistribute it and/or modify 00008 // it under the terms of the GNU General Public License as published by 00009 // the Free Software Foundation; either version 2 of the License, or 00010 // (at your option) any later version. 00011 // 00012 // MCS is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 // 00017 // You should have received a copy of the GNU General Public License 00018 // along with MCS; if not, write to the Free Software 00019 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00020 // 00021 // ----------------------------------------------------------------------$ 00022 00023 #include <assert.h> 00024 00025 #include "mcs.hh" 00026 using namespace mcs; 00027 00028 #ifndef HAVE_PTHREAD_MUTEXATTR_SETTYPE 00029 extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) 00030 __THROW; 00031 #endif 00032 00033 00034 00035 00036 //-------------------------------------------------------- 00037 mcs::Synchro::Synchro() 00038 { 00039 MCS_DEBUG_SETUP(0, "Synchro"); 00040 MCS_DEBUG_ENTER(NOARGS); 00041 00042 Count = 0; 00043 isActive = false; 00044 00045 MCS_DEBUG_LEAVE(NOARGS); 00046 } 00047 00048 00049 mcs::Synchro::~Synchro() 00050 { 00051 MCS_DEBUG_ENTER(NOARGS); 00052 00053 synchronize(false); 00054 00055 MCS_DEBUG_LEAVE(NOARGS); 00056 } 00057 00058 int mcs::Synchro::count() 00059 { return Count; } 00060 00061 00062 void mcs::Synchro::synchronize(bool setactive) 00063 { 00064 MCS_DEBUG_ENTER( << isActive); 00065 00066 if (Count != 0) 00067 throw MCS_FATAL( MSG_CANT_SET_SYNCHRO_STATE ); 00068 00069 if ((! isActive) && (setactive)) { 00070 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); 00071 #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL 00072 pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE); 00073 #endif 00074 pthread_mutex_init(&mutex, &attr); 00075 } 00076 00077 if ((isActive) && (! setactive)) { 00078 int ret = pthread_mutex_destroy(&mutex); 00079 assert(ret == 0); 00080 } 00081 00082 isActive = setactive; 00083 MCS_DEBUG_LEAVE( << isActive ); 00084 } 00085 00086 00087 bool mcs::Synchro::enter(int op, unsigned int to) 00088 { 00089 int ret = 0; 00090 00091 if (! isActive) return true; 00092 MCS_DEBUG_ENTER(NOARGS); 00093 00094 switch (op) { 00095 case MCS_SYNCHRO_LOCK: 00096 ret = pthread_mutex_lock(&mutex); 00097 break; 00098 case MCS_SYNCHRO_TRY_LOCK: 00099 ret = pthread_mutex_trylock(&mutex); 00100 break; 00101 case MCS_SYNCHRO_TRY_TIMED: 00102 struct timeval now; 00103 struct timespec timeout; 00104 unsigned int millisec, seconds; 00105 millisec = to % 1000; 00106 seconds = (unsigned int) floor((double) (to / 1000.0)); 00107 gettimeofday(&now, NULL); 00108 timeout.tv_sec = now.tv_sec + seconds; 00109 timeout.tv_nsec = now.tv_usec * 1000 + millisec * 1000000; 00110 00111 ret = pthread_mutex_timedlock(&mutex, &timeout); 00112 break; 00113 } 00114 00115 assert((ret == 0) || 00116 (ret == EBUSY) || 00117 (ret == ETIMEDOUT) ); 00118 00119 00120 if (ret == 0) { 00121 Count++; 00122 } 00123 00124 00125 MCS_DEBUG_LEAVE(NOARGS); 00126 return (ret == 0); 00127 } 00128 00129 00130 00131 int mcs::Synchro::leave() 00132 { 00133 if (! isActive) return 0; 00134 MCS_DEBUG_ENTER(<< Count); 00135 00136 int ret; 00137 ret = pthread_mutex_unlock(&mutex); 00138 00139 assert(ret == 0); 00140 00141 if (ret == 0) 00142 Count--; 00143 00144 return Count; 00145 MCS_DEBUG_LEAVE(NOARGS); 00146 } 00147 00148 00149 bool mcs::Synchro::tryenter(unsigned int timeout) 00150 { 00151 if (timeout == 0) 00152 return enter(MCS_SYNCHRO_TRY_LOCK); 00153 else 00154 return enter(MCS_SYNCHRO_TRY_TIMED, timeout); 00155 } 00156 00157 00158 00159 //bool mcs::Synchro::wait(unsigned int to) 00160 //{ 00161 // int ret; 00162 // bool bret; 00163 // if (! isActive) return true; 00164 // 00165 // //waiting = true; 00166 // 00167 // MCS_DEBUG_ENTER(NOARGS); 00168 // 00169 // //Always use TIMED wait. 00170 // struct timeval now; 00171 // struct timespec timeout; 00172 // unsigned int millisec, seconds; 00173 // millisec = to % 1000; 00174 // seconds = (unsigned int) floor((double) (to / 1000.0)); 00175 // gettimeofday(&now, NULL); 00176 // timeout.tv_sec = now.tv_sec + seconds; 00177 // timeout.tv_nsec = now.tv_usec * 1000 + millisec * 1000000; 00178 // 00179 // ret = pthread_cond_timedwait(&cond, &mutex, &timeout); 00180 // bret = (! ((ret == ETIMEDOUT) || (ret == EINTR))); 00181 // 00182 // waiting = false; 00183 // MCS_DEBUG_LEAVE(NOARGS); 00184 // return bret; 00185 //} 00186 00187 00188 00189 00190 00191 00192 00193 00194 //-------------------------------------------------------- 00195 mcs::Thread::Thread(int id, Thread* parent) : syn_lstate() 00196 { 00197 MCS_DEBUG_SETUP(0, "Thread"); 00198 00199 lparent = parent; 00200 lid = id; 00201 lerror = NULL; 00202 00203 lstate = MCS_STATE_CREATED; 00204 syn_lstate.synchronize(true); 00205 00206 detached = false; 00207 selfDelete = false; 00208 00209 MCS_DEBUG_LEAVE(<< lid); 00210 } 00211 00212 00213 mcs::Thread::~Thread() 00214 { 00215 MCS_DEBUG_ENTER(<< lid); 00216 if (pthread_self() != lthrID) 00217 stop(); 00218 00219 if (lerror) 00220 delete lerror; 00221 MCS_DEBUG_LEAVE(<< lid); 00222 } 00223 00224 void mcs::Thread::initial() 00225 {} 00226 00227 void mcs::Thread::final() 00228 {} 00229 00230 00231 int mcs::Thread::state() 00232 { return lstate; } 00233 00234 int mcs::Thread::id() 00235 { return lid; } 00236 00237 Event* mcs::Thread::error() 00238 { return lerror; } 00239 00240 Thread* mcs::Thread::parent() 00241 { return lparent; } 00242 00243 void mcs::Thread::cleanup_Handler(void* p) 00244 { ((Thread*) p)->final(); } 00245 00246 00247 void mcs::Thread::run() 00248 { throw MCS_ERROR(MSG_METHOD_MUST_BE_OVERLOADED, "Thread::run"); } 00249 00250 void mcs::Thread::notify(int id, Thread* ref) 00251 { 00252 #if ENABLE_DEBUG 00253 char buf[10]; 00254 sprintf(buf, "%d", id); 00255 string s = "Notify from " + string(buf); 00256 MCS_DEBUG(lid << " " << s.c_str()); 00257 #endif 00258 } 00259 00260 00261 00262 void mcs::Thread::set_cancel_state(bool cancel) 00263 { 00264 int ret; 00265 if (cancel) { 00266 ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 00267 assert(ret == 0); 00268 ret = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 00269 assert(ret == 0); 00270 } 00271 else { 00272 ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 00273 assert(ret == 0); 00274 } 00275 } 00276 00277 00278 void mcs::Thread::test_cancel() 00279 { 00280 int old, ret; 00281 ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old); 00282 assert(ret == 0); 00283 ret = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); 00284 assert(ret == 0); 00285 00286 pthread_testcancel(); 00287 00288 ret = pthread_setcancelstate(old, NULL); 00289 assert(ret == 0); 00290 } 00291 00292 00293 00294 void mcs::Thread::startDetached(bool selfdelete) 00295 { 00296 detached = true; 00297 selfDelete = selfdelete; 00298 start(); 00299 } 00300 00301 00302 void mcs::Thread::start() 00303 { 00304 int ret; 00305 MCS_DEBUG_ENTER(<< lid); 00306 00307 ret = pthread_create(<hrID, NULL, Thread::RunThread, this); 00308 if (ret) 00309 throw MCS_FATAL(MSG_CALLING_PTHREAD_CREATE); 00310 00311 if (detached) { 00312 ret = pthread_detach(lthrID); 00313 if (ret != 0) 00314 throw MCS_FATAL(MSG_CALLING_PTHREAD_CREATE); 00315 } 00316 00317 //Continue only after initial() have been executed 00318 while (lstate < MCS_STATE_RUNNING) 00319 sleep_ms(1); 00320 00321 MCS_DEBUG_LEAVE(<< lid); 00322 } 00323 00324 00325 00326 void* mcs::Thread::RunThread(void* args) 00327 { 00328 Thread* thr = (Thread*) args; 00329 00330 //Install the cleanup handler 00331 pthread_cleanup_push(cleanup_Handler, thr); 00332 00333 thr->set_cancel_state(true); 00334 00335 try { 00336 thr->initial(); 00337 thr->lstate = MCS_STATE_RUNNING; 00338 00339 //From the run() method it is possible to 00340 // - return 00341 // - throw an exception 00342 // - another thread call the stop() method 00343 thr->run(); 00344 } 00345 catch (Event e) { 00346 thr->lerror = new Event(e); 00347 //cerr << e.msg() << endl; 00348 } 00349 00350 thr->set_cancel_state(false); 00351 00352 if (thr->checkTerminating()) { 00353 pthread_exit(NULL); 00354 return NULL; 00355 } 00356 00357 pthread_cleanup_pop(0); 00358 thr->final(); 00359 00360 thr->lstate = MCS_STATE_END; 00361 00362 //The thread is terminating by itself and will eventually notify its 00363 //parent who won't call the stop() method. In this case the 00364 //pthread_cancel and pthread_join functions won't be called and the 00365 //resources won't be freed. Calling pthread_detach() here will 00366 //detach the thread and resources will be freed at the 00367 //pthread_exit() call. 00368 pthread_detach(thr->lthrID); 00369 00370 if (thr->lparent) 00371 thr->lparent->notify(thr->lid, thr); 00372 00373 if (thr->selfDelete) 00374 delete thr; 00375 00376 00377 pthread_exit(NULL); 00378 return NULL; 00379 } 00380 00381 00382 00383 void mcs::Thread::stop() 00384 { 00385 //This method MUST not be called from the thread itself 00386 assert(pthread_self() != lthrID); 00387 00388 if (detached) 00389 return; //ERROR: Can't stop a detached thread 00390 00391 bool wasterminating = checkTerminating(); 00392 //If the thread was already terminating the rest of the job has been 00393 //performed in the RunThread() method, so we can return. 00394 if (wasterminating) 00395 return; 00396 00397 //If the thread is not detached then the parent thread MUST call 00398 //pthread_cancel() and pthread_join() to free resources. 00399 00400 pthread_cancel(lthrID); //final() will be called here if the cleanup 00401 //handler is still installed 00402 pthread_join(lthrID, NULL); 00403 00404 //Il controllo wasterminating ==> return era qui. 00405 00406 lstate = MCS_STATE_END; 00407 00408 if (lparent) 00409 lparent->notify(lid, this); 00410 } 00411 00412 00413 bool mcs::Thread::checkTerminating() 00414 { 00415 bool ret; 00416 00417 syn_lstate.enter(); 00418 ret = (lstate >= MCS_STATE_TERMINATING); 00419 if (!ret) 00420 lstate = MCS_STATE_TERMINATING; 00421 syn_lstate.leave(); 00422 00423 return ret; 00424 } 00425 00426 00427 00428 00429 00430 mcs::ThreadFunc::ThreadFunc(int (*start_routine)(void*), 00431 void* arg) : 00432 Thread(0, NULL) 00433 { 00434 this->start_routine1 = start_routine; 00435 this->start_routine2 = NULL; 00436 this->arg = arg; 00437 ret = 0; 00438 } 00439 00440 mcs::ThreadFunc::ThreadFunc(Event* (*start_routine)(void*), 00441 void* arg) : 00442 Thread(0, NULL) 00443 { 00444 this->start_routine1 = NULL; 00445 this->start_routine2 = start_routine; 00446 this->arg = arg; 00447 ret = 0; 00448 } 00449 00450 00451 void mcs::ThreadFunc::run() 00452 { 00453 if (start_routine1) 00454 ret = (start_routine1)(arg); 00455 else 00456 lerror = (start_routine2)(arg); 00457 } 00458 00459 int mcs::ThreadFunc::retcode() 00460 { return ret; } 00461 00462 00463 00464 00465 00466 00467 00468 void mcs::sleep_ms(unsigned int millisec) 00469 { 00470 struct timespec tt, tmp; 00471 tt.tv_sec = 0; 00472 tt.tv_nsec = 0; 00473 00474 00475 if (millisec >= 1000) { 00476 tt.tv_sec = ((long int) (millisec / 1000.0)); 00477 } 00478 00479 tt.tv_nsec = (millisec % 1000) * 1000000; 00480 nanosleep(&tt, &tmp); 00481 } 00482 00483 00484
![]() |
MCS (My Customizable Server) ver. 0.3.3-alpha3
|