MCS  0.3.3-alpha7
Thread.cc
1 // ----------------------------------------------------------------------^
2 // Copyright (C) 2004, 2005, 2006, 2007, 2008 Giorgio Calderone
3 // (mailto: <gcalderone@ifc.inaf.it>)
4 //
5 // This file is part of MCS.
6 //
7 // MCS is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // MCS is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with MCS; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // ----------------------------------------------------------------------$
22 
23 #include <assert.h>
24 
25 #include "mcs.hh"
26 using namespace mcs;
27 
28 #ifndef HAVE_PTHREAD_MUTEXATTR_SETTYPE
29 extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind)
30  __THROW;
31 #endif
32 
33 
34 
35 /*Begin Pierre debug stuff*/
36 
37 #define TBOLD "\x1B[1m"
38 #define REV "\x1B[7m"
39 #define RED "\x1B[31m"
40 #define GREEN "\x1B[32m"
41 #define BLUE "\x1B[34m"
42 #define CYAN "\x1B[36m"
43 #define YELLOW "\x1B[33m"
44 #define MAGENTA "\x1B[35m"
45 #define BEEP "\x7"
46 #define BGBLUE "\x1B[44m"
47 #define NORMAL "\x1B[0m"
48 #define CLEANS "\x1B[2J"
49 
50 
51 #define MERROR std::cerr << RED << "\r(E)\t"<< GREEN << __FILE__ << "," << __LINE__ << NORMAL << "\t" <<TBOLD<<__FUNCTION__<<NORMAL << "\t"
52 #define MINFO std::cout << BLUE << "\r(I)\t"<< GREEN << __FILE__ << "," << __LINE__ << NORMAL << "\t" <<TBOLD<<__FUNCTION__<<NORMAL << "\t"
53 #define MWARN std::cout << YELLOW << "\r(W)\t"<< GREEN << __FILE__ << "," << __LINE__ << NORMAL << "\t" <<TBOLD<<__FUNCTION__<<NORMAL << "\t"
54 
55 /*End Pierre debug stuff */
56 
57 //--------------------------------------------------------
59 {
60 
61  MCS_DEBUG_SETUP(0, "Synchro");
62  MCS_DEBUG_ENTER(NOARGS);
63 
64  Count = 0;
65  isActive = false;
66 
67  //MINFO << "synchro ptr ("<< this <<") created!"<<endl;
68 
69  // MCS_DEBUG_LEAVE(NOARGS);
70 }
71 
72 
74 {
75 
76  MCS_DEBUG_ENTER(NOARGS);
77 
78  synchronize(false);
79 
80  MCS_DEBUG_LEAVE(NOARGS);
81 
82 
83 }
84 
86 { return Count; }
87 
88 
89 void mcs::Synchro::synchronize(bool setactive)
90 {
91  MCS_DEBUG_ENTER( << isActive);
92 
93  if (Count != 0)
94  throw MCS_FATAL( MSG_CANT_SET_SYNCHRO_STATE );
95 
96  if ((! isActive) && (setactive)) {
97 //LN-darwin
98 /*
99  One of PTHREAD_MUTEX_RECURSIVE_NP and PTHREAD_MUTEX_RECURSIVE seem to be
100  present in different versions. For example, Mac OS X 10.4 had
101  PTHREAD_MUTEX_RECURSIVE_NP but Mac OS X 10.5 does not; instead it has
102  PTHREAD_MUTEX_RECURSIVE
103  */
104 
105 
106 #ifdef HAVE_PTHREAD_MUTEX_RECURSIVE_NP
107 #define PTHREAD_MUTEX_RECURSIVE_VALUE PTHREAD_MUTEX_RECURSIVE_NP
108 #elif defined (HAVE_PTHREAD_MUTEX_RECURSIVE)
109 #define PTHREAD_MUTEX_RECURSIVE_VALUE PTHREAD_MUTEX_RECURSIVE
110 #else
111 #define PTHREAD_MUTEX_RECURSIVE_VALUE PTHREAD_MUTEX_RECURSIVE
112 #error 'Unable to determine pthread mutex recursive value'
113 #endif /* pthread mutex recursive value */
114 
115  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_VALUE);
116 #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
117  pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE);
118 #endif
119 //LN-darwin: apparently any attribute setting causes failure!
120 #ifdef __APPLE__
121  pthread_mutex_init(&mutex, NULL);
122 #else
123  pthread_mutex_init(&mutex, &attr);
124 #endif
125 
126 
127 
128  }
129 
130 
131 
132 
133  if ((isActive) && (! setactive)) {
134  int ret = pthread_mutex_destroy(&mutex);
135  assert(ret == 0);
136  }
137 
138  isActive = setactive;
139  MCS_DEBUG_LEAVE( << isActive );
140 }
141 
142 
143 bool mcs::Synchro::enter(int op, unsigned int to)
144 {
145  int ret = 0;
146 
147  if (! isActive) return true;
148  MCS_DEBUG_ENTER(NOARGS);
149 
150  switch (op) {
151  case MCS_SYNCHRO_LOCK:
152  ret = pthread_mutex_lock(&mutex);
153  break;
155  ret = pthread_mutex_trylock(&mutex);
156  break;
158  struct timeval now;
159  struct timespec timeout;
160  unsigned int millisec, seconds;
161  millisec = to % 1000;
162  seconds = (unsigned int) floor((double) (to / 1000.0));
163  gettimeofday(&now, NULL);
164  timeout.tv_sec = now.tv_sec + seconds;
165  timeout.tv_nsec = now.tv_usec * 1000 + millisec * 1000000;
166 
167 //LN-darwin
168 #if defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS - 200112L) >= 0L
169  ret = pthread_mutex_timedlock(&mutex, &timeout);
170 #else
171  ret = pthread_mutex_lock(&mutex);
172 #endif
173  break;
174  }
175 
176 //MINFO<<"pthread_mutex_lock ret="<<ret<<
177 // " EDEADLK:"<<EDEADLK<<" EAGAIN:"<<EAGAIN<<" EINVAL:"<<EINVAL<<endl;
178  assert((ret == 0) ||
179  (ret == EBUSY) ||
180  (ret == ETIMEDOUT) );
181 
182 
183  if (ret == 0) {
184  Count++;
185  }
186 
187 
188  MCS_DEBUG_LEAVE(NOARGS);
189  return (ret == 0);
190 }
191 
192 
193 
195 {
196  if (! isActive) return 0;
197  MCS_DEBUG_ENTER(<< Count);
198 
199  int ret;
200  ret = pthread_mutex_unlock(&mutex);
201 
202  assert(ret == 0);
203 
204  if (ret == 0)
205  Count--;
206 
207  return Count;
208  MCS_DEBUG_LEAVE(NOARGS);
209 }
210 
211 
212 bool mcs::Synchro::tryenter(unsigned int timeout)
213 {
214  if (timeout == 0)
215  return enter(MCS_SYNCHRO_TRY_LOCK);
216  else
217  return enter(MCS_SYNCHRO_TRY_TIMED, timeout);
218 }
219 
220 
221 
222 //bool mcs::Synchro::wait(unsigned int to)
223 //{
224 // int ret;
225 // bool bret;
226 // if (! isActive) return true;
227 //
228 // //waiting = true;
229 //
230 // MCS_DEBUG_ENTER(NOARGS);
231 //
232 // //Always use TIMED wait.
233 // struct timeval now;
234 // struct timespec timeout;
235 // unsigned int millisec, seconds;
236 // millisec = to % 1000;
237 // seconds = (unsigned int) floor((double) (to / 1000.0));
238 // gettimeofday(&now, NULL);
239 // timeout.tv_sec = now.tv_sec + seconds;
240 // timeout.tv_nsec = now.tv_usec * 1000 + millisec * 1000000;
241 //
242 // ret = pthread_cond_timedwait(&cond, &mutex, &timeout);
243 // bret = (! ((ret == ETIMEDOUT) || (ret == EINTR)));
244 //
245 // waiting = false;
246 // MCS_DEBUG_LEAVE(NOARGS);
247 // return bret;
248 //}
249 
250 
251 
252 
253 
254 
255 
256 
257 //--------------------------------------------------------
258 mcs::Thread::Thread(int id, Thread* parent) //: syn_lstate()
259 {
260 
261  // MCS_DEBUG_SETUP(0, "Thread");
262 
263  lparent = parent;
264  lid = id;
265  lerror = NULL;
266 
267  //MINFO << "Thread init lerror is null ? "<< lerror << endl;
268 
269  lstate = MCS_STATE_CREATED;
270  // syn_lstate.synchronize(true);
271 
272  detached = false;
273  selfDelete = false;
274 
275  // MCS_DEBUG_LEAVE(<< lid);
276 }
277 
278 
280 {
281 
282  //MINFO << "Thread "<< id() <<" delete lerror = " << lerror <<endl;
283 
284  MCS_DEBUG_ENTER(<< lid);
285  if (pthread_self() != lthrID){
286  stop();
287  }
288 
289  if (lerror){
290  //MINFO << id() << " : delete lerror "<< lerror << endl;
291  delete lerror;
292  lerror=0;
293  //MINFO << id() << " : delete lerror done "<< endl;
294  }
295  MCS_DEBUG_LEAVE(<< lid);
296 
297  //MINFO << "thread "<< id() <<" delete... done"<<endl;
298 }
299 
301 {}
302 
304 {}
305 
306 
308 { return lstate; }
309 
311 { return lid; }
312 
314 { return lerror; }
315 
317 { return lparent; }
318 
320 { ((Thread*) p)->final(); }
321 
322 
324 { throw MCS_ERROR(MSG_METHOD_MUST_BE_OVERLOADED, "Thread::run"); }
325 
326 void mcs::Thread::notify(int id, Thread* ref)
327 {
328 #if ENABLE_DEBUG
329  char buf[10];
330  sprintf(buf, "%d", id);
331  string s = "Notify from " + string(buf);
332  MCS_DEBUG(lid << " " << s.c_str());
333 #endif
334 }
335 
336 
337 
339 {
340  int ret;
341  if (cancel) {
342  ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
343  assert(ret == 0);
344  ret = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
345  assert(ret == 0);
346  }
347  else {
348  ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
349  assert(ret == 0);
350  }
351 }
352 
353 
355 {
356  int old, ret;
357  ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
358  assert(ret == 0);
359  ret = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
360  assert(ret == 0);
361 
362  pthread_testcancel();
363 
364  ret = pthread_setcancelstate(old, NULL);
365  assert(ret == 0);
366 }
367 
368 
369 
370 void mcs::Thread::startDetached(bool selfdelete)
371 {
372  detached = true;
373  selfDelete = selfdelete;
374  start();
375 }
376 
377 
379 {
380 
381 
382  //MINFO << "ID " << id() <<" Starting from main thread: lerror is " << lerror << endl;
383 
384  int ret;
385 
386  MCS_DEBUG_ENTER(<< lid);
387 
388 
389 
390  ret = pthread_create(&lthrID, NULL, mcs::Thread::RunThread, this);
391 
392  if (ret)
393  throw MCS_FATAL(MSG_CALLING_PTHREAD_CREATE);
394 
395  if (detached) {
396 
397  ret = pthread_detach(lthrID);
398 
399  if (ret != 0)
400  throw MCS_FATAL(MSG_CALLING_PTHREAD_CREATE);
401  }
402 
403  //Continue only after initial() have been executed
404 
405  while (lstate < MCS_STATE_RUNNING)
406  sleep_ms(1);
407 
408  MCS_DEBUG_LEAVE(<< lid);
409 }
410 
411 
412 
413 void* mcs::Thread::RunThread(void* args)
414 {
415  Thread* thr = (Thread*) args;
416 
417  //MINFO << "ID " << thr->id() <<" Beginning : lerror is " << thr->lerror << endl;
418 
419  //Install the cleanup handler
420 
421  pthread_cleanup_push(mcs::Thread::cleanup_Handler, thr);
422  thr->set_cancel_state(true);
423 
424  try {
425  thr->initial();
426  thr->lstate = MCS_STATE_RUNNING;
427 
428 
429  //From the run() method it is possible to
430  // - return
431  // - throw an exception
432  // - another thread call the stop() method
433  //MINFO << "ID " << thr->id() <<" Before run : lerror is " << thr->lerror << endl;
434 
435  thr->run();
436 
437  //MINFO << "ID " << thr->id() << " After run : lerror is " << thr->lerror << endl;
438  }
439  catch (Event e) {
440  //MINFO << "creating lerror " << endl;
441 
442  thr->lerror = new Event(e);
443  //cerr << e.msg() << endl;
444  }
445 
446  //MINFO << thr->id() << " : Finished execution : lerror is " << thr->lerror << endl;
447 
448 
449  thr->set_cancel_state(false);
450 
451  if (thr->checkTerminating()) {
452  pthread_exit(NULL);
453  return NULL;
454  }
455 
456  pthread_cleanup_pop(0);
457 
458  thr->final();
459 
460  thr->lstate = MCS_STATE_END;
461 
462  //The thread is terminating by itself and will eventually notify its
463  //parent who won't call the stop() method. In this case the
464  //pthread_cancel and pthread_join functions won't be called and the
465  //resources won't be freed. Calling pthread_detach() here will
466  //detach the thread and resources will be freed at the
467  //pthread_exit() call.
468 
469  pthread_detach(thr->lthrID);
470 
471  if (thr->lparent)
472  thr->lparent->notify(thr->lid, thr);
473 
474  if (thr->selfDelete){
475  MWARN << " AUTO delete !!!! " << endl;
476 
477  delete thr;
478 
479  MWARN << " AUTO delete !!!! I survived !!" << endl;
480  }
481 
482 
483  //MINFO << thr->id() << " : Finished cleanup : lerror is " << thr->lerror << endl;
484 
485  if((long int) thr->lerror == 1){
486  MERROR << "Thread "<< thr->id() <<" Ohh lerror is 1? !"<< thr->lerror << endl;
487  }else
488 
489  if( thr->lerror!=NULL){
490  //MINFO << thr->id() << " Exiting with non-null lerror, deleteing : lerror->where()= " << thr->lerror->where() << endl;
491 
492  delete thr->lerror;
493  thr->lerror=0;
494  //MINFO << thr->id() << " deleting lerror OK " << endl;
495  }
496 
497  // pthread_exit(NULL);
498 
499  // MINFO << " Exiting 2 " << endl;
500 
501 
502  return NULL;
503 }
504 
505 
506 
508 {
509 
510  //This method MUST not be called from the thread itself
511  assert(pthread_self() != lthrID);
512 
513  if (detached)
514  return; //ERROR: Can't stop a detached thread
515 
516  bool wasterminating = checkTerminating();
517  //If the thread was already terminating the rest of the job has been
518  //performed in the RunThread() method, so we can return.
519  if (wasterminating)
520  return;
521 
522  //If the thread is not detached then the parent thread MUST call
523  //pthread_cancel() and pthread_join() to free resources.
524 
525  pthread_cancel(lthrID); //final() will be called here if the cleanup
526  //handler is still installed
527  pthread_join(lthrID, NULL);
528 
529  //Il controllo wasterminating ==> return era qui.
530 
531  lstate = MCS_STATE_END;
532 
533  if (lparent)
534  lparent->notify(lid, this);
535 }
536 
537 
539 {
540  bool ret;
541 
542  // syn_lstate.enter();
543 
544  ret = (lstate >= MCS_STATE_TERMINATING);
545  if (!ret)
546  lstate = MCS_STATE_TERMINATING;
547 
548  // syn_lstate.leave();
549 
550  return ret;
551 }
552 
553 
554 
555 
556 
557 mcs::ThreadFunc::ThreadFunc(int (*start_routine)(void*),
558  void* arg) :
559  Thread(0, NULL)
560 {
561  this->start_routine1 = start_routine;
562  this->start_routine2 = NULL;
563  this->arg = arg;
564  ret = 0;
565 }
566 
567 mcs::ThreadFunc::ThreadFunc(Event* (*start_routine)(void*),
568  void* arg) :
569  Thread(0, NULL)
570 {
571  this->start_routine1 = NULL;
572  this->start_routine2 = start_routine;
573  this->arg = arg;
574  ret = 0;
575 }
576 
577 
578 void mcs::ThreadFunc::run()
579 {
580 
581  //MINFO << "lerror is " << lerror << endl;
582 
583  if (start_routine1)
584  ret = (start_routine1)(arg);
585  else{
586  //MINFO << "Creating lerror in RUN "<<endl;
587  lerror = (start_routine2)(arg);
588  //MINFO << "Creating lerror in RUN lerror="<< lerror <<endl;
589  }
590 
591  //MINFO << "lerror is " << lerror << endl;
592 }
593 
594 int mcs::ThreadFunc::retcode()
595 { return ret; }
596 
597 
598 
599 
600 
601 
602 
603 void mcs::sleep_ms(unsigned int millisec)
604 {
605  struct timespec tt, tmp;
606  tt.tv_sec = 0;
607  tt.tv_nsec = 0;
608 
609 
610  if (millisec >= 1000) {
611  tt.tv_sec = ((long int) (millisec / 1000.0));
612  }
613 
614  tt.tv_nsec = (millisec % 1000) * 1000000;
615  nanosleep(&tt, &tmp);
616 }
617 
618 
619 
bool enter(int op=1, unsigned int timeout=0)
Enter, or try to enter a critical section.
Definition: Thread.cc:143
bool checkTerminating()
Starting point for the separate thread.
Definition: Thread.cc:538
virtual ~Thread()
Destructor.
Definition: Thread.cc:279
int lid
General purpose Thread identifier.
Definition: mcs.hh:2502
bool tryenter(unsigned int timeout=0)
Wrapper around enter(), using op=MCS_SYNCHRO_TRY_LOCK if the parameter is 0, op=MCS_SYNCHRO_TRY_TIMED...
Definition: Thread.cc:212
int id()
Returns the Thread object identificator.
Definition: Thread.cc:310
virtual void notify(int id, Thread *ref)
A method called from child threads to notify their termination.
Definition: Thread.cc:326
void startDetached(bool selfDelete=false)
Start a new thread in the detached state.
Definition: Thread.cc:370
virtual void initial()
Initialization method.
Definition: Thread.cc:300
void start()
Start a new thread in the joinable state.
Definition: Thread.cc:378
void stop()
Stop thread execution.
Definition: Thread.cc:507
#define MCS_STATE_END
Thread state: the separate thread had terminated its execution.
Definition: mcs.hh:2416
static void cleanup_Handler(void *This)
Static wrapper around final().
Definition: Thread.cc:319
Event * lerror
Last error.
Definition: mcs.hh:2614
Synchro()
Constructor.
Definition: Thread.cc:58
void synchronize(bool setactive)
Enable or disable the synchronization feature.
Definition: Thread.cc:89
Hold informations about an event.
Definition: mcs.hh:814
#define MCS_SYNCHRO_TRY_LOCK
To be used with Synchro.enter(): try to enter a critical section.
Definition: mcs.hh:2262
#define MCS_SYNCHRO_LOCK
To be used with Synchro.enter(): enter a critical section.
Definition: mcs.hh:2259
Thread * parent()
Returns the address of the parent.
Definition: Thread.cc:316
int count()
Return how many times the current thread has locked the section.
Definition: Thread.cc:85
pthread_t lthrID
System&#39;s thread identifier.
Definition: mcs.hh:2499
void sleep_ms(unsigned int millisec)
A millisecond resolution sleep function.
Definition: Thread.cc:603
#define MCS_ERROR(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:964
Event * error()
Return last error message.
Definition: Thread.cc:313
#define MCS_STATE_CREATED
Thread state: the object has been created ut the separate thread has not been started.
Definition: mcs.hh:2406
#define MCS_SYNCHRO_TRY_TIMED
To be used with Synchro.enter(): try to enter a critical section with timeout facility.
Definition: mcs.hh:2266
ThreadFunc(int(*start_routine)(void *), void *arg)
Constructor, run a user function in a separate thread.
Definition: Thread.cc:557
Thread * lparent
Reference to parent Thread object, if any is given in the constructor.
Definition: mcs.hh:2496
#define MCS_STATE_TERMINATING
Thread state: the exit() method is executing, the separate thread is going to execute the final() met...
Definition: mcs.hh:2413
Main include file for all MCS based applications.
int lstate
State of the object, see state() method.
Definition: mcs.hh:2505
#define MCS_STATE_RUNNING
Thread state: the separate thread is executing the run() method.
Definition: mcs.hh:2409
virtual void final()
Finalization method.
Definition: Thread.cc:303
void set_cancel_state(bool cancel)
Set cancellation state for current thread.
Definition: Thread.cc:338
void test_cancel()
Test if a cancellation request is pending.
Definition: Thread.cc:354
A class to create separate threads.
Definition: mcs.hh:2487
bool selfDelete
Tell if the object should delete himself once the thread is terminated.
Definition: mcs.hh:2532
#define MCS_FATAL(A, rest...)
Facility to easily pass all necessary parameter to an Event constructor.
Definition: mcs.hh:967
Thread(int id=0, Thread *parent=NULL)
Declared to avoid using of default copy constructor.
Definition: Thread.cc:258
~Synchro()
Destructor.
Definition: Thread.cc:73
int state()
Return the state of the thread.
Definition: Thread.cc:307
virtual void run()
Body of the thread execution.
Definition: Thread.cc:323
int leave()
Leave a critical section.
Definition: Thread.cc:194
Namespace for MCS library.

mcslogo

MCS (My Customizable Server) ver. 0.3.3-alpha7
Documentation generated on Mon May 28 07:39:41 UTC 2018