/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- poll
- pselect
- select
- signalfd
- eventfd
- epoll_create
- epoll_create1
- epoll_ctl
- epoll_wait
- inotify_init
- inotify_init1
- inotify_init
- inotify_init1
- inotify_add_watch
- inotify_rm_watch
1 /****************************************************************************
2 * Copyright (C) 2012 by Kapil Arya, Gene Cooperman, and Rohan Garg *
3 * kapil@ccs.neu.edu, gene@ccs.neu.edu, rohgarg@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 <poll.h>
23 #include <sys/select.h>
24 /* According to POSIX.1-2001 */
25 #include <sys/select.h>
26 /* Next three according to earlier standards */
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include "dmtcpalloc.h"
31 #include "eventwrappers.h"
32 #include "eventconnection.h"
33 #include "eventconnlist.h"
34 #include "jassert.h"
35
36 using namespace dmtcp;
37 /* 'man 7 signal' says the following are not restarted after ckpt signal
38 * even though the SA_RESTART option was used. If we wrap these, we must
39 * restart them when they are interrupted by a checkpoint signal.
40 * python-2.7{socketmodule.c,signalmodule.c} assume no unknown signal
41 * handlers such as DMTCP checkpoint signal. So, Python needs this.
42 *
43 * + Socket interfaces, when a timeout has been set on the socket
44 * using setsockopt(2): accept(2), recv(2), recvfrom(2), and
45 * recvmsg(2), if a receive timeout (SO_RCVTIMEO) has been set;
46 * connect(2), send(2), sendto(2), and sendmsg(2), if a send timeout
47 * (SO_SNDTIMEO) has been set.
48 *
49 * + Interfaces used to wait for signals: pause(2), sigsuspend(2),
50 * sigtimedwait(2), and sigwaitinfo(2).
51 *
52 * + File descriptor multiplexing interfaces: epoll_wait(2),
53 * epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).
54 *
55 * + System V IPC interfaces: msgrcv(2), msgsnd(2), semop(2), and
56 * semtimedop(2).
57 *
58 * + Sleep interfaces: clock_nanosleep(2), nanosleep(2), and usleep(3).
59 *
60 * + read(2) from an inotify(7) file descriptor.
61 *
62 * + io_getevents(2).
63 */
64
65 // TODO(kapil): A better way to fix this is to lookup the stack to check if we
66 // are in the middle of a poll/select/pselect call and set some global variable
67 // and restart the syscall only if that variable is set.
68
69 /* Poll wrapper forces poll to restart after ckpt/resume or ckpt/restart */
70 extern "C" int poll(struct pollfd *fds, nfds_t nfds, int timeout)
71 {
72 int rc;
73 while (1) {
74 uint32_t orig_generation = dmtcp_get_generation();
75 rc = _real_poll(fds, nfds, timeout);
76 if (rc == -1 && errno == EINTR &&
77 dmtcp_get_generation() > orig_generation) {
78 continue; // This was a restart or resume after checkpoint.
79 } else {
80 break; // The signal interrupting us was not our checkpoint signal.
81 }
82 }
83 return rc;
84 }
85
86
87 // pselect wrapper forces pselect to restart after ckpt/resume or ckpt/restart
88 extern "C" int pselect(int nfds, fd_set *readfds, fd_set *writefds,
89 fd_set *exceptfds, const struct timespec *timeout,
90 const sigset_t *sigmask)
91 {
92 int rc;
93 while (1) {
94 uint32_t orig_generation = dmtcp_get_generation();
95 rc = _real_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask);
96 if (rc == -1 && errno == EINTR &&
97 dmtcp_get_generation() > orig_generation) {
98 continue; // This was a restart or resume after checkpoint.
99 } else {
100 break; // The signal interrupting us was not our checkpoint signal.
101 }
102 }
103 return rc;
104 }
105
106
107 extern "C" int select(int nfds, fd_set *readfds, fd_set *writefds,
108 fd_set *exceptfds, struct timeval *timeout)
109 {
110 int rc;
111 while (1) {
112 uint32_t orig_generation = dmtcp_get_generation();
113 rc = _real_select(nfds, readfds, writefds, exceptfds, timeout);
114 if (rc == -1 && errno == EINTR &&
115 dmtcp_get_generation() > orig_generation) {
116 continue; // This was a restart or resume after checkpoint.
117 } else {
118 break; // The signal interrupting us was not our checkpoint signal.
119 }
120 }
121 return rc;
122 }
123
124
125 /****************************************************************************
126 ****************************************************************************/
127
128 #ifdef HAVE_SYS_SIGNALFD_H
129 extern "C" int signalfd(int fd, const sigset_t *mask, int flags)
130 {
131 DMTCP_PLUGIN_DISABLE_CKPT();
132 int ret = _real_signalfd(fd, mask, flags);
133 if (ret != -1) {
134 JTRACE("signalfd created") (fd) (flags);
135 EventConnList::instance().add(ret, new SignalFdConnection(fd, mask, flags));
136 }
137 DMTCP_PLUGIN_ENABLE_CKPT();
138 return ret;
139 }
140 #endif
141
142 #ifdef HAVE_SYS_EVENTFD_H
143 extern "C" int eventfd(EVENTFD_VAL_TYPE initval, int flags)
144 {
145 DMTCP_PLUGIN_DISABLE_CKPT();
146 int ret = _real_eventfd(initval, flags);
147 if (ret != -1) {
148 JTRACE("eventfd created") (ret) (initval) (flags);
149 EventConnList::instance().add(ret, new EventFdConnection(initval, flags));
150 }
151 DMTCP_PLUGIN_ENABLE_CKPT();
152 return ret;
153 }
154 #endif
155
156 #ifdef HAVE_SYS_EPOLL_H
157 extern "C" int epoll_create(int size)
158 {
159 DMTCP_PLUGIN_DISABLE_CKPT();
160 int ret = _real_epoll_create(size);
161 if (ret != -1) {
162 JTRACE("epoll fd created") (ret) (size);
163 EventConnList::instance().add(ret, new EpollConnection(size));
164 }
165 DMTCP_PLUGIN_ENABLE_CKPT();
166 return ret;
167 }
168
169 extern "C" int epoll_create1(int flags)
170 {
171 DMTCP_PLUGIN_DISABLE_CKPT();
172 int ret = _real_epoll_create1(flags);
173 if (ret != -1) {
174 JTRACE("epoll fd created1") (ret) (flags);
175 EventConnList::instance().add(ret, new EpollConnection(flags));
176 }
177 DMTCP_PLUGIN_ENABLE_CKPT();
178 return ret;
179 }
180
181 extern "C" int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
182 {
183 DMTCP_PLUGIN_DISABLE_CKPT();
184 int ret = _real_epoll_ctl(epfd, op, fd, event);
185 if (ret != -1) {
186 //JTRACE("epoll fd CTL") (ret) (epfd) (fd) (op);
187 EpollConnection *con =
188 (EpollConnection*) EventConnList::instance().getConnection(epfd);
189 con->onCTL(op, fd, event);
190 }
191 DMTCP_PLUGIN_ENABLE_CKPT();
192 return ret;
193 }
194
195 extern "C" int epoll_wait(int epfd, struct epoll_event *events, int maxevents,
196 int timeout)
197 {
198 int readyFds = 0;
199 int timeLeft = timeout;
200 int mytime;
201 // JTRACE("Starting to do wait on epoll fd");
202
203 if (timeout >= 0 && timeout < 1000) {
204 // Short time intervals
205 DMTCP_PLUGIN_DISABLE_CKPT();
206 readyFds = _real_epoll_wait(epfd, events, maxevents, timeout);
207 DMTCP_PLUGIN_ENABLE_CKPT();
208 return readyFds;
209 } else if (timeout >= 1000) {
210 mytime = 1000; // wait time quanta: 1000 ms
211 } else {
212 // In case of indefinite timeout, start with 0 and increment by 1ms.
213 mytime = 0;
214 }
215
216 do {
217 DMTCP_PLUGIN_DISABLE_CKPT();
218 readyFds = _real_epoll_wait(epfd, events, maxevents, mytime);
219 DMTCP_PLUGIN_ENABLE_CKPT();
220 if (timeout < 0 && mytime <= 100) {
221 // Increase timeout if we are going to wait forever.
222 mytime += 1;
223 } else {
224 timeLeft -= mytime;
225 }
226 } while ((timeLeft > 0 || timeout < 0) && readyFds == 0);
227 return readyFds;
228 }
229 #endif
230
231
232 #ifdef HAVE_SYS_INOTIFY_H
233 #ifndef DMTCP_USE_INOTIFY
234 EXTERNC int inotify_init()
235 {
236 JWARNING(false) .Text("Inotify not yet supported by DMTCP");
237 errno = ENOMEM;
238 return -1;
239 }
240
241 EXTERNC int inotify_init1(int flags)
242 {
243 JWARNING(false) .Text("Inotify not yet supported by DMTCP");
244 errno = ENOMEM;
245 return -1;
246 }
247 #else
248 /******************************************************************
249 * function name: inotify_init()
250 *
251 * description: monitors file system events
252 *
253 * para: none
254 * return: fd (inotify instance)
255 ******************************************************************/
256 EXTERNC int inotify_init()
257 {
258 int fd;
259 DMTCP_PLUGIN_DISABLE_CKPT();
260 JTRACE("Starting to create an inotify fd.");
261 fd = _real_inotify_init();
262 if (fd > 0) {
263 JTRACE ( "inotify fd created" ) ( ret );
264 //create the inotify object
265 Connection *con = new InotifyConnection(0);
266 EventConnList::instance().add(ret, con);
267 }
268 DMTCP_PLUGIN_ENABLE_CKPT();
269 return fd;
270 }
271
272 /******************************************************************
273 * function name: inotify_init1()
274 *
275 * description: monitors file system events
276 *
277 * para: flags
278 * return: fd (inotify instance)
279 ******************************************************************/
280 EXTERNC int inotify_init1(int flags)
281 {
282 DMTCP_PLUGIN_DISABLE_CKPT();
283 int ret = _real_inotify_init1(flags);
284 if (ret != -1) {
285 JTRACE("inotify1 fd created") (ret) (flags);
286 Connection *con = new InotifyConnection(flags);
287 EventConnList::instance().add(ret, flags);
288 }
289 DMTCP_PLUGIN_ENABLE_CKPT();
290 return ret;
291 }
292
293 /******************************************************************
294 * function name: inotify_add_watch()
295 *
296 * description: adds a directory or file to be watched
297 *
298 * para: fd - inotify instance
299 * para: pathname - directory or file
300 * para: mask - events to be monitored on pathname
301 * return: watch descriptor (wd) on success, -1 on failure
302 ******************************************************************/
303 EXTERNC int inotify_add_watch(int fd, const char *pathname, uint32_t mask)
304 {
305 DMTCP_PLUGIN_DISABLE_CKPT();
306 int ret = _real_inotify_add_watch(fd, pathname, mask);
307 if (ret != -1) {
308 JTRACE("calling inotify class methods");
309 InotifyConnection& inotify_con =
310 (InotifyConnection*) EventConnList::instance().getConnection(fd);
311
312 inotify_con->add_watch_descriptors(ret, fd, pathname, mask);
313 /*temp_pathname = pathname;
314 inotify_con.map_inotify_fd_to_wd ( fd, ret);
315 inotify_con.map_wd_to_pathname(ret, temp_pathname);
316 inotify_con.map_pathname_to_mask(temp_pathname, mask);*/
317 }
318 DMTCP_PLUGIN_ENABLE_CKPT();
319 return ret;
320 }
321
322 /******************************************************************
323 * function name: inotify_rm_watch()
324 *
325 * description: removes the watch descriptor associated with
326 * the inotify instance
327 *
328 * para: fd - inotify instance
329 * para: wd - watch descriptor to be removed
330 * return: 0 on success, -1 on failure
331 ******************************************************************/
332 EXTERNC int inotify_rm_watch(int fd, int wd)
333 {
334 DMTCP_PLUGIN_DISABLE_CKPT(); // The lock is released inside the macro.
335 int ret = _real_inotify_rm_watch(fd, wd);
336 if (ret != -1) {
337 JTRACE("remove inotify mapping from dmtcp") (ret) (fd) (wd);
338 InotifyConnection& inotify_con =
339 (InotifyConnection*) EventConnList::instance().getConnection(fd);
340 //inotify_con.remove_mappings(fd, wd);
341 inotify_con->remove_watch_descriptors(wd);
342 }
343 DMTCP_PLUGIN_ENABLE_CKPT();
344 return ret;
345 }
346 #endif
347 #endif