/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- shmget
- shmat
- shmdt
- shmctl
- semget
- semop
- semtimedop
- semctl
- msgget
- msgsnd
- msgrcv
- msgctl
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 // msgrcv has confliciting return types on some systems (e.g. SLES 10)
23 // So, we temporarily rename it so that type declarations are not for msgrcv.
24 #define msgrcv msgrcv_glibc
25
26 #include <sys/ipc.h>
27 #include <sys/shm.h>
28 #include <stdarg.h>
29
30 #undef msgrcv
31
32 #include "dmtcp.h"
33 #include "sysvipc.h"
34 #include "sysvipcwrappers.h"
35 #include "jassert.h"
36
37 using namespace dmtcp;
38
39 static struct timespec ts_100ms = {0, 100 * 1000 * 1000};
40 /******************************************************************************
41 *
42 * SysV Shm Methods
43 *
44 *****************************************************************************/
45
46 extern "C"
47 int shmget(key_t key, size_t size, int shmflg)
48 {
49 int realId = -1;
50 int virtId = -1;
51 DMTCP_PLUGIN_DISABLE_CKPT();
52 realId = _real_shmget(key, size, shmflg);
53 if (realId != -1) {
54 SysVShm::instance().on_shmget(realId, key, size, shmflg);
55 virtId = REAL_TO_VIRTUAL_SHM_ID(realId);
56 JTRACE ("Creating new Shared memory segment")
57 (key) (size) (shmflg) (realId) (virtId);
58 }
59 DMTCP_PLUGIN_ENABLE_CKPT();
60 return virtId;
61 }
62
63 extern "C"
64 void *shmat(int shmid, const void *shmaddr, int shmflg)
65 {
66 DMTCP_PLUGIN_DISABLE_CKPT();
67 int realShmid = VIRTUAL_TO_REAL_SHM_ID(shmid);
68 JASSERT(realShmid != -1) .Text("Not Implemented");
69 void *ret = _real_shmat(realShmid, shmaddr, shmflg);
70 #ifdef __arm__
71 // This is arguably a bug in Linux kernel 2.6.28, 2.6.29, 3.0 - 3.2 and others
72 // See: https://bugs.kde.org/show_bug.cgi?id=222545
73 // On ARM, SHMLBA == 4*PAGE_SIZE instead of PAGESIZE
74 // So, this fails:
75 // shmaddr = shmat(shmid, NULL, 0); smdt(shmaddr); shmat(shmid, shaddr, 0);
76 // when shmaddr % 0x4000 != 0 (when shmaddr not multiple of SMLBA)
77 // Workaround for bug in Linux kernel for ARM follows.
78 // WHEN KERNEL FIX IS AVAILABLE, DO THIS ONLY FOR BUGGY KERNEL VERSIONS.
79 if (((long)ret % 0x4000 != 0) && (ret != (void *)-1)) { // if ret%SHMLBA != 0
80 void *ret_addr[20];
81 unsigned int i;
82 for (i = 0; i < sizeof(ret_addr) / sizeof(ret_addr[0]) ; i++) {
83 ret_addr[i] = ret; // Save bad address for detaching later
84 ret = _real_shmat(realShmid, shmaddr, shmflg); // Try again
85 // if ret % SHMLBA == 0 { ... }
86 if (((long)ret % 0x4000 == 0) || (ret == (void *)-1))
87 break; // Good address (or error return)
88 }
89 // Detach all the bad addresses athat are not SHMLBA-aligned.
90 if (i < sizeof(ret_addr) / sizeof(ret_addr[0]))
91 for (unsigned int j = 0; j < i+1; j++)
92 _real_shmdt( ret_addr[j] );
93 JASSERT((long)ret % 0x4000 == 0)
94 (shmaddr) (shmflg) (getpid())
95 .Text ("Failed to get SHMLBA-aligned address after 20 tries");
96 }
97 #elif defined(__aarch64__)
98 # warning "TODO: Implementation for ARM64."
99 #endif
100
101 if (ret != (void *) -1) {
102 SysVShm::instance().on_shmat(shmid, shmaddr, shmflg, ret);
103 JTRACE ("Mapping Shared memory segment") (shmid) (realShmid) (shmflg) (ret);
104 }
105 DMTCP_PLUGIN_ENABLE_CKPT();
106 return ret;
107 }
108
109 extern "C"
110 int shmdt(const void *shmaddr)
111 {
112 DMTCP_PLUGIN_DISABLE_CKPT();
113 int ret = _real_shmdt(shmaddr);
114 if (ret != -1) {
115 SysVShm::instance().on_shmdt(shmaddr);
116 JTRACE ("Unmapping Shared memory segment" ) (shmaddr);
117 }
118 DMTCP_PLUGIN_ENABLE_CKPT();
119 return ret;
120 }
121
122 extern "C"
123 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
124 {
125 DMTCP_PLUGIN_DISABLE_CKPT();
126 int realShmid = VIRTUAL_TO_REAL_SHM_ID(shmid);
127 JASSERT(realShmid != -1);
128 int ret = _real_shmctl(realShmid, cmd, buf);
129 DMTCP_PLUGIN_ENABLE_CKPT();
130 return ret;
131 }
132
133 /******************************************************************************
134 *
135 * SysV Semaphore Methods
136 *
137 *****************************************************************************/
138
139 extern "C"
140 int semget(key_t key, int nsems, int semflg)
141 {
142 int realId = -1;
143 int virtId = -1;
144 DMTCP_PLUGIN_DISABLE_CKPT();
145 realId = _real_semget (key, nsems, semflg);
146 if (realId != -1) {
147 SysVSem::instance().on_semget(realId, key, nsems, semflg);
148 virtId = REAL_TO_VIRTUAL_SEM_ID(realId);
149 JTRACE ("Creating new SysV Semaphore" ) (key) (nsems) (semflg);
150 }
151 DMTCP_PLUGIN_ENABLE_CKPT();
152 return virtId;
153 }
154
155 extern "C"
156 int semop(int semid, struct sembuf *sops, size_t nsops)
157 {
158 return semtimedop(semid, sops, nsops, NULL);
159 }
160
161 extern "C"
162 int semtimedop(int semid, struct sembuf *sops, size_t nsops,
163 const struct timespec *timeout)
164 {
165 struct timespec totaltime = {0, 0};
166 int ret;
167 int realId;
168 bool ipc_nowait_specified = false;
169
170 for (size_t i = 0; i < nsops; i++) {
171 if (sops[i].sem_flg & IPC_NOWAIT) {
172 ipc_nowait_specified = true;
173 break;
174 }
175 }
176
177 if (ipc_nowait_specified ||
178 (timeout != NULL && TIMESPEC_CMP(timeout, &ts_100ms, <))) {
179 DMTCP_PLUGIN_DISABLE_CKPT();
180 realId = VIRTUAL_TO_REAL_SEM_ID(semid);
181 JASSERT(realId != -1);
182 ret = _real_semtimedop(realId, sops, nsops, timeout);
183 if (ret == 0) {
184 SysVSem::instance().on_semop(semid, sops, nsops);
185 }
186 DMTCP_PLUGIN_ENABLE_CKPT();
187 return ret;
188 }
189
190 /*
191 * We continue to call pthread_tryjoin_np (and sleep) until we have gone past
192 * the abstime provided by the caller
193 */
194 while (timeout == NULL || TIMESPEC_CMP(&totaltime, timeout, <)) {
195 ret = EAGAIN;
196 DMTCP_PLUGIN_DISABLE_CKPT();
197 realId = VIRTUAL_TO_REAL_SEM_ID(semid);
198 JASSERT(realId != -1);
199 ret = _real_semtimedop(realId, sops, nsops, &ts_100ms);
200 if (ret == 0) {
201 SysVSem::instance().on_semop(semid, sops, nsops);
202 }
203 DMTCP_PLUGIN_ENABLE_CKPT();
204
205 // TODO Handle EIDRM
206 if (ret == 0 ||
207 (ret == -1 && errno != EAGAIN)) {
208 return ret;
209 }
210
211 TIMESPEC_ADD(&totaltime, &ts_100ms, &totaltime);
212 }
213 errno = EAGAIN;
214 return -1;
215 }
216
217 extern "C"
218 int semctl(int semid, int semnum, int cmd, ...)
219 {
220 union semun uarg;
221 va_list arg;
222 va_start (arg, cmd);
223 uarg = va_arg (arg, union semun);
224 va_end (arg);
225
226 DMTCP_PLUGIN_DISABLE_CKPT();
227 int realId = VIRTUAL_TO_REAL_SEM_ID(semid);
228 JASSERT(realId != -1);
229 int ret = _real_semctl(realId, semnum, cmd, uarg);
230 if (ret != -1) {
231 SysVSem::instance().on_semctl(semid, semnum, cmd, uarg);
232 }
233 DMTCP_PLUGIN_ENABLE_CKPT();
234 return ret;
235 }
236 /******************************************************************************
237 *
238 * SysV Msg Queue Methods
239 *
240 *****************************************************************************/
241
242 extern "C"
243 int msgget(key_t key, int msgflg)
244 {
245 int realId = -1;
246 int virtId = -1;
247 DMTCP_PLUGIN_DISABLE_CKPT();
248 realId = _real_msgget (key, msgflg);
249 if (realId != -1) {
250 SysVMsq::instance().on_msgget(realId, key, msgflg);
251 virtId = REAL_TO_VIRTUAL_MSQ_ID(realId);
252 JTRACE ("Creating new SysV Msg Queue" ) (key) (msgflg);
253 }
254 DMTCP_PLUGIN_ENABLE_CKPT();
255 return virtId;
256 }
257
258 extern "C"
259 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
260 {
261 int ret;
262 int realId;
263
264 /*
265 * We continue to call msgsnd with IPC_NOWAIT (and sleep) until we succeed
266 * or fail with something other than EAGAIN
267 * If IPC_NOWAIT was specified and msgsnd fails with EAGAIN, return.
268 */
269 while (true) {
270 DMTCP_PLUGIN_DISABLE_CKPT();
271 realId = VIRTUAL_TO_REAL_MSQ_ID(msqid);
272 JASSERT(realId != -1);
273 ret = _real_msgsnd(realId, msgp, msgsz, msgflg | IPC_NOWAIT);
274 if (ret == 0) {
275 SysVMsq::instance().on_msgsnd(msqid, msgp, msgsz, msgflg);
276 }
277 DMTCP_PLUGIN_ENABLE_CKPT();
278
279 // TODO Handle EIDRM
280 if ((ret == 0) ||
281 (ret == -1 && errno != EAGAIN) ||
282 (msgflg & IPC_NOWAIT)) {
283 return ret;
284 }
285
286 nanosleep(&ts_100ms, NULL);
287 }
288 JASSERT(false) .Text("Not Reached");
289 return -1;
290 }
291
292 extern "C"
293 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
294 {
295 int ret;
296 int realId;
297
298 /*
299 * We continue to call msgrcv with IPC_NOWAIT (and sleep) until we succeed
300 * or fail with something other than EAGAIN
301 * If IPC_NOWAIT was specified and msgsnd fails with EAGAIN, return.
302 */
303 while (true) {
304 DMTCP_PLUGIN_DISABLE_CKPT();
305 realId = VIRTUAL_TO_REAL_MSQ_ID(msqid);
306 JASSERT(realId != -1);
307 ret = _real_msgrcv(realId, msgp, msgsz, msgtyp, msgflg | IPC_NOWAIT);
308 if (ret == 0) {
309 SysVMsq::instance().on_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
310 }
311 DMTCP_PLUGIN_ENABLE_CKPT();
312
313 // TODO Handle EIDRM
314 if ((ret >= 0) ||
315 (ret == -1 && errno != ENOMSG) ||
316 (msgflg & IPC_NOWAIT)) {
317 return ret;
318 }
319
320 nanosleep(&ts_100ms, NULL);
321 }
322 JASSERT(false) .Text("Not Reached");
323 return -1;
324 }
325
326
327 extern "C"
328 int msgctl(int msqid, int cmd, struct msqid_ds *buf)
329 {
330 DMTCP_PLUGIN_DISABLE_CKPT();
331 int realId = VIRTUAL_TO_REAL_MSQ_ID(msqid);
332 JASSERT(realId != -1);
333 int ret = _real_msgctl(realId, cmd, buf);
334 if (ret != -1) {
335 SysVMsq::instance().on_msgctl(msqid, cmd, buf);
336 }
337 DMTCP_PLUGIN_ENABLE_CKPT();
338 return ret;
339 }