/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- _do_lock_tbl
- _do_unlock_tbl
- dmtcp_event_hook
- instance
- removeStaleClockIds
- resetOnFork
- preCheckpoint
- postRestart
- getoverrun
- on_timer_create
- on_timer_delete
- on_timer_settime
- on_clock_getcpuclockid
- 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 }