root/plugin/timer/timerlist.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _do_lock_tbl
  2. _do_unlock_tbl
  3. dmtcp_event_hook
  4. instance
  5. removeStaleClockIds
  6. resetOnFork
  7. preCheckpoint
  8. postRestart
  9. getoverrun
  10. on_timer_create
  11. on_timer_delete
  12. on_timer_settime
  13. on_clock_getcpuclockid
  14. on_pthread_getcpuclockid

   1 /****************************************************************************
   2  *   Copyright (C) 2006-2010 by Jason Ansel, Kapil Arya, and Gene Cooperman *
   3  *   jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu              *
   4  *                                                                          *
   5  *   This file is part of the dmtcp/src module of DMTCP (DMTCP:dmtcp/src).  *
   6  *                                                                          *
   7  *  DMTCP:dmtcp/src is free software: you can redistribute it and/or        *
   8  *  modify it under the terms of the GNU Lesser General Public License as   *
   9  *  published by the Free Software Foundation, either version 3 of the      *
  10  *  License, or (at your option) any later version.                         *
  11  *                                                                          *
  12  *  DMTCP:dmtcp/src 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 Lesser General Public License for more details.                     *
  16  *                                                                          *
  17  *  You should have received a copy of the GNU Lesser General Public        *
  18  *  License along with DMTCP:dmtcp/src.  If not, see                        *
  19  *  <http://www.gnu.org/licenses/>.                                         *
  20  ****************************************************************************/
  21 
  22 #include <time.h>
  23 #include "timerlist.h"
  24 #include "timerwrappers.h"
  25 
  26 using namespace dmtcp;
  27 
  28 static TimerList *_timerlist = NULL;
  29 
  30 static pthread_mutex_t timerLock = PTHREAD_MUTEX_INITIALIZER;
  31 static void _do_lock_tbl()
  32 {
  33   JASSERT(_real_pthread_mutex_lock(&timerLock) == 0) (JASSERT_ERRNO);
  34 }
  35 
  36 static void _do_unlock_tbl()
  37 {
  38   JASSERT(_real_pthread_mutex_unlock(&timerLock) == 0) (JASSERT_ERRNO);
  39 }
  40 
  41 extern "C"
  42 void dmtcp_event_hook(DmtcpEvent_t event, DmtcpEventData_t *data)
  43 {
  44   if (_timerlist != NULL) {
  45     switch (event) {
  46       case DMTCP_EVENT_ATFORK_CHILD:
  47         TimerList::instance().resetOnFork();
  48         break;
  49 
  50       case DMTCP_EVENT_WRITE_CKPT:
  51         TimerList::instance().preCheckpoint();
  52         break;
  53 
  54       case DMTCP_EVENT_RESTART:
  55         TimerList::instance().postRestart();
  56         break;
  57 
  58       default:
  59         break;
  60     }
  61   }
  62 
  63   DMTCP_NEXT_EVENT_HOOK(event, data);
  64 }
  65 
  66 TimerList& TimerList::instance()
  67 {
  68   if (_timerlist == NULL) {
  69     _timerlist = new TimerList();
  70   }
  71   return *_timerlist;
  72 }
  73 
  74 void TimerList::removeStaleClockIds()
  75 {
  76   // remove stale clockids
  77   vector<clockid_t> staleClockIds;
  78   map<clockid_t, pid_t>::iterator clockPidListIter;
  79   for (clockPidListIter = _clockPidList.begin();
  80        clockPidListIter != _clockPidList.end();
  81        clockPidListIter++) {
  82     pid_t pid = clockPidListIter->second;
  83     clockid_t realId = VIRTUAL_TO_REAL_CLOCK_ID(clockPidListIter->first);
  84     clockid_t clockid;
  85     if (_real_clock_getcpuclockid(pid, &clockid) != 0 || clockid != realId) {
  86       staleClockIds.push_back(clockPidListIter->first);
  87     }
  88   }
  89   for (size_t i = 0; i < staleClockIds.size(); i++) {
  90     JTRACE("Removing stale clock") (staleClockIds[i]);
  91     _clockPidList.erase(staleClockIds[i]);
  92   }
  93   staleClockIds.clear();
  94 
  95   map<clockid_t, pthread_t>::iterator clockPthreadListIter;
  96   for (clockPthreadListIter = _clockPthreadList.begin();
  97        clockPthreadListIter != _clockPthreadList.end();
  98        clockPthreadListIter++) {
  99     pthread_t pth = clockPthreadListIter->second;
 100     clockid_t realId = VIRTUAL_TO_REAL_CLOCK_ID(clockPthreadListIter->first);
 101     clockid_t clockid;
 102     if (_real_pthread_getcpuclockid(pth, &clockid) != 0 || clockid != realId) {
 103       staleClockIds.push_back(clockPthreadListIter->first);
 104     }
 105   }
 106   for (size_t i = 0; i < staleClockIds.size(); i++) {
 107     JNOTE("Removing stale clock") (staleClockIds[i]);
 108     _clockPthreadList.erase(staleClockIds[i]);
 109   }
 110 }
 111 
 112 void TimerList::resetOnFork()
 113 {
 114   _timerInfo.clear();
 115   //_clockPidList.clear();
 116   //_clockPthreadList.clear();
 117   _timerVirtIdTable.clear();
 118   pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 119   timerLock = lock;
 120   _clockVirtIdTable.resetOnFork((clockid_t) (unsigned) getpid());
 121 }
 122 
 123 void TimerList::preCheckpoint()
 124 {
 125   removeStaleClockIds();
 126   for (_iter = _timerInfo.begin(); _iter != _timerInfo.end(); _iter++) {
 127     timer_t virtId = _iter->first;
 128     timer_t realId = VIRTUAL_TO_REAL_TIMER_ID(virtId);
 129     TimerInfo& tinfo = _iter->second;
 130     JASSERT(_real_timer_gettime(realId, &tinfo.curr_timerspec) == 0)
 131       (virtId) (realId) (JASSERT_ERRNO);
 132     tinfo.overrun = _real_timer_getoverrun(realId);
 133   }
 134 }
 135 
 136 void TimerList::postRestart()
 137 {
 138   // Refresh clockids
 139   map<clockid_t, pid_t>::iterator it1;
 140   for (it1 = _clockPidList.begin(); it1 != _clockPidList.end(); it1++) {
 141     pid_t pid = it1->second;
 142     clockid_t virtId = it1->first;
 143     clockid_t realId;
 144     JASSERT(_real_clock_getcpuclockid(pid, &realId) == 0) (pid) (JASSERT_ERRNO);
 145     _clockVirtIdTable.updateMapping(virtId, realId);
 146   }
 147 
 148   map<clockid_t, pthread_t>::iterator it2;
 149   for (it2 = _clockPthreadList.begin(); it2 != _clockPthreadList.end(); it2++) {
 150     pthread_t pth = it2->second;
 151     clockid_t virtId = it2->first;
 152     clockid_t realId;
 153     JASSERT(_real_pthread_getcpuclockid(pth, &realId) == 0) (pth)
 154       (JASSERT_ERRNO);
 155     _clockVirtIdTable.updateMapping(virtId, realId);
 156   }
 157 
 158   // Refresh timers
 159   for (_iter = _timerInfo.begin(); _iter != _timerInfo.end(); _iter++) {
 160     timer_t realId;
 161     timer_t virtId = _iter->first;
 162     struct sigevent *sevp = NULL;
 163     TimerInfo& tinfo = _iter->second;
 164     clockid_t clockid = VIRTUAL_TO_REAL_CLOCK_ID(tinfo.clockid);
 165     if (!tinfo.sevp_null) {
 166       sevp = &tinfo.sevp;
 167     }
 168     JASSERT(_real_timer_create(clockid, sevp, &realId) == 0)
 169       (virtId) (JASSERT_ERRNO);
 170     _timerVirtIdTable.updateMapping(virtId, realId);
 171     if (tinfo.curr_timerspec.it_value.tv_sec != 0 ||
 172         tinfo.curr_timerspec.it_value.tv_nsec != 0) {
 173       struct itimerspec tspec;
 174       if (tinfo.flags & TIMER_ABSTIME) {
 175         // The timer should expire when the clock time equals the time
 176         // specified in initial_timerspec.
 177         // FIXME: For clocks measugin CPU time for processes and threads, such
 178         // as CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID, we need to
 179         // adjust the value of initial_timerspec to allow
 180         // the changes on the time on these clocks after restart.
 181         tspec = tinfo.initial_timerspec;
 182       } else {
 183         tspec = tinfo.curr_timerspec;
 184       }
 185       JASSERT(_real_timer_settime(realId, tinfo.flags, &tspec, NULL) == 0)
 186         (virtId) (JASSERT_ERRNO);
 187       JTRACE("Restoring timer") (realId) (virtId);
 188     }
 189   }
 190 }
 191 
 192 int TimerList::getoverrun(timer_t id)
 193 {
 194   _do_lock_tbl();
 195   JASSERT(_timerInfo.find(id) != _timerInfo.end());
 196   int ret = _timerInfo[id].overrun;
 197   _timerInfo[id].overrun = 0;
 198   _do_unlock_tbl();
 199   return ret;
 200 }
 201 
 202 timer_t TimerList::on_timer_create(timer_t realId, clockid_t clockid,
 203                                 struct sigevent *sevp)
 204 {
 205   TimerInfo tinfo;
 206   timer_t virtId;
 207   _do_lock_tbl();
 208   JASSERT(!_timerVirtIdTable.realIdExists(realId)) (realId);
 209 
 210   JASSERT(_timerVirtIdTable.getNewVirtualId(&virtId));
 211   _timerVirtIdTable.updateMapping(virtId, realId);
 212 
 213   memset(&tinfo, 0, sizeof(tinfo));
 214   tinfo.clockid = clockid;
 215   if (sevp == NULL) {
 216     tinfo.sevp_null = true;
 217   } else {
 218     tinfo.sevp_null = false;
 219     tinfo.sevp = *sevp;
 220   }
 221 
 222   _timerInfo[virtId] = tinfo;
 223   _do_unlock_tbl();
 224   return virtId;
 225 }
 226 
 227 void TimerList::on_timer_delete(timer_t timerid)
 228 {
 229   _do_lock_tbl();
 230   _timerVirtIdTable.erase(timerid);
 231   JASSERT(_timerInfo.find(timerid) != _timerInfo.end());
 232   _timerInfo.erase(timerid);
 233   _do_unlock_tbl();
 234 }
 235 
 236 void TimerList::on_timer_settime(timer_t timerid, int flags,
 237                                  const struct itimerspec *new_value)
 238 {
 239   _do_lock_tbl();
 240   JASSERT(_timerInfo.find(timerid) != _timerInfo.end());
 241   _timerInfo[timerid].flags = flags;
 242   _timerInfo[timerid].initial_timerspec = *new_value;
 243   _do_unlock_tbl();
 244 }
 245 
 246 clockid_t TimerList::on_clock_getcpuclockid(pid_t pid, clockid_t realId)
 247 {
 248   _do_lock_tbl();
 249   if (_clockVirtIdTable.size() > 800) {
 250     removeStaleClockIds();
 251   }
 252   clockid_t virtId;
 253   JASSERT(_clockVirtIdTable.getNewVirtualId(&virtId));
 254   _clockPidList[virtId] = pid;
 255   _clockVirtIdTable.updateMapping(virtId, realId);
 256   _do_unlock_tbl();
 257   return virtId;
 258 }
 259 
 260 clockid_t TimerList::on_pthread_getcpuclockid(pthread_t thread, clockid_t realId)
 261 {
 262   _do_lock_tbl();
 263   _clockPthreadList[realId] = thread;
 264   if (_clockVirtIdTable.size() > 800) {
 265     removeStaleClockIds();
 266   }
 267   clockid_t virtId;
 268   JASSERT(_clockVirtIdTable.getNewVirtualId(&virtId));
 269   _clockVirtIdTable.updateMapping(virtId, realId);
 270   _do_unlock_tbl();
 271   return virtId;
 272 }

/* [<][>][^][v][top][bottom][index][help] */