/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- pidVirt_pthread_atfork_child
- __register_atfork
- fork
- clone_start
- __clone
- shmctl
- semctl
- msgctl
- clock_getcpuclockid
- timer_create
- mq_notify
- syscall
1 /****************************************************************************
2 * Copyright (C) 2006-2013 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 <semaphore.h>
23 #include <sys/syscall.h>
24 #ifdef __aarch64__
25 # define __ARCH_WANT_SYSCALL_DEPRECATED
26 // SYS_getpgrp is a deprecated kernel call in aarch64, but in favor of what?
27 # include <asm-generic/unistd.h>
28 // SYS_getpgrp undefined in aarch64, but add extra insurance
29 # undef SYS_getpgrp
30 # define SYS_getpgrp __NR_getpgrp
31 #endif
32 #include <linux/version.h>
33
34 #include "jassert.h"
35 #include "jfilesystem.h"
36 #include "jconvert.h"
37 #include "pidwrappers.h"
38 #include "virtualpidtable.h"
39 #include "dmtcp.h"
40 #include "shareddata.h"
41 #include "util.h"
42 #include "pid.h"
43
44 using namespace dmtcp;
45
46 LIB_PRIVATE pid_t getPidFromEnvVar();
47
48 void pidVirt_pthread_atfork_child()
49 {
50 dmtcpResetPidPpid();
51 dmtcpResetTid(getpid());
52 VirtualPidTable::instance().resetOnFork();
53 }
54
55 extern "C" int __register_atfork(void (*prepare)(void), void (*parent)(void),
56 void (*child)(void), void *dso_handle)
57 {
58 /* dmtcp_prepare_wrappers() must be called before __register_atfork().
59 * NEXT_FNC() guarantees that dmtcp_prepare_wrappers() is called if
60 * it was not called earlier. */
61 return NEXT_FNC(__register_atfork)(prepare, parent, child, dso_handle);
62 }
63
64 extern "C" pid_t fork()
65 {
66 pid_t retval = 0;
67 pid_t virtualPid = getPidFromEnvVar();
68
69 VirtualPidTable::instance().writeVirtualTidToFileForPtrace(virtualPid);
70
71 pid_t realPid = _real_fork();
72
73 if (realPid > 0) { /* Parent Process */
74 retval = virtualPid;
75 VirtualPidTable::instance().updateMapping(virtualPid, realPid);
76 SharedData::setPidMap(virtualPid, realPid);
77 } else {
78 retval = realPid;
79 VirtualPidTable::instance().readVirtualTidFromFileForPtrace();
80 }
81
82 return retval;
83 }
84
85 struct ThreadArg {
86 int (*fn) (void *arg); // clone() calls fn that returns int
87 void *arg;
88 pid_t virtualTid;
89 sem_t sem;
90 };
91
92 // Invoked via __clone
93 LIB_PRIVATE
94 int clone_start(void *arg)
95 {
96 struct ThreadArg *threadArg = (struct ThreadArg*) arg;
97 int (*fn) (void *) = threadArg->fn;
98 void *thread_arg = threadArg->arg;
99 pid_t virtualTid = threadArg -> virtualTid;
100
101 if (dmtcp_is_running_state()) {
102 dmtcpResetTid(virtualTid);
103 }
104
105 VirtualPidTable::instance().updateMapping(virtualTid, _real_gettid());
106 sem_post(&threadArg->sem);
107
108 JTRACE("Calling user function") (virtualTid);
109 return (*fn) (thread_arg);
110 }
111
112
113 typedef int (*clone_fptr_t)(int (*fn) (void *arg), void *child_stack, int
114 flags, void *arg, int *parent_tidptr,
115 struct user_desc *newtls, int *child_tidptr);
116 //need to forward user clone
117 extern "C" int __clone(int (*fn) (void *arg), void *child_stack, int flags,
118 void *arg, int *parent_tidptr, struct user_desc *newtls,
119 int *child_tidptr)
120 {
121 pid_t virtualTid = -1;
122 struct MtcpRestartThreadArg *mtcpRestartThreadArg;
123
124 if (!dmtcp_is_running_state()) {
125 mtcpRestartThreadArg = (struct MtcpRestartThreadArg *) arg;
126 arg = mtcpRestartThreadArg -> arg;
127 virtualTid = mtcpRestartThreadArg -> virtualTid;
128 if (virtualTid != VIRTUAL_TO_REAL_PID(virtualTid)) {
129 VirtualPidTable::instance().postRestart();
130 }
131 } else {
132 virtualTid = VirtualPidTable::instance().getNewVirtualTid();
133 VirtualPidTable::instance().writeVirtualTidToFileForPtrace(virtualTid);
134 }
135
136 // We have to use DMTCP-specific memory allocator because using glibc:malloc
137 // can interfere with user threads.
138 // We use JALLOC_HELPER_FREE to free this memory in two places:
139 // 1. later in this function in case of failure on call to __clone; and
140 // 2. near the beginnging of clone_start (wrapper for start_routine).
141 struct ThreadArg *threadArg =
142 (struct ThreadArg *) JALLOC_HELPER_MALLOC(sizeof (struct ThreadArg));
143 threadArg->fn = fn;
144 threadArg->arg = arg;
145 threadArg->virtualTid = virtualTid;
146 sem_init(&threadArg->sem, 0, 0);
147
148 JTRACE("Calling libc:__clone");
149 pid_t tid = _real_clone(clone_start, child_stack, flags, threadArg,
150 parent_tidptr, newtls, child_tidptr);
151
152 if (dmtcp_is_running_state()) {
153 VirtualPidTable::instance().readVirtualTidFromFileForPtrace();
154 }
155
156 if (tid > 0) {
157 JTRACE("New thread created") (tid);
158 /* Wait for child thread to finish intializing.
159 * We must let the child thread insert original->current tid in the
160 * virtualpidtable. If we don't wait for the child thread and update the
161 * pidtable ourselves, there is a possible race if the child thread is
162 * short lived. In that case, the parent thread might insert
163 * original->current mapping well after the child thread has exited causing
164 * stale entries in the virtualpidtable.
165 */
166 sem_wait(&threadArg->sem);
167 sem_destroy(&threadArg->sem);
168 } else {
169 virtualTid = tid;
170 }
171 // Free memory previously allocated by calling JALLOC_HELPER_MALLOC
172 JALLOC_HELPER_FREE(threadArg);
173 return virtualTid;
174 }
175
176 extern "C"
177 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
178 {
179 DMTCP_PLUGIN_DISABLE_CKPT();
180 int ret = _real_shmctl(shmid, cmd, buf);
181 if (buf != NULL) {
182 buf->shm_cpid = REAL_TO_VIRTUAL_PID(buf->shm_cpid);
183 buf->shm_lpid = REAL_TO_VIRTUAL_PID(buf->shm_lpid);
184 }
185 DMTCP_PLUGIN_ENABLE_CKPT();
186 return ret;
187 }
188
189 extern "C"
190 int semctl(int semid, int semnum, int cmd, ...)
191 {
192 union semun uarg;
193 va_list arg;
194 va_start (arg, cmd);
195 uarg = va_arg (arg, union semun);
196 va_end (arg);
197
198 DMTCP_PLUGIN_DISABLE_CKPT();
199 int ret = _real_semctl(semid, semnum, cmd, uarg);
200 if (ret != -1 && (cmd & GETPID)) {
201 ret = REAL_TO_VIRTUAL_PID(ret);
202 }
203 DMTCP_PLUGIN_ENABLE_CKPT();
204 return ret;
205 }
206
207 extern "C"
208 int msgctl(int msqid, int cmd, struct msqid_ds *buf)
209 {
210 DMTCP_PLUGIN_DISABLE_CKPT();
211 int ret = _real_msgctl(msqid, cmd, buf);
212 if (ret != -1 && buf != NULL && ((cmd & IPC_STAT) || (cmd & MSG_STAT))) {
213 buf->msg_lspid = REAL_TO_VIRTUAL_PID(buf->msg_lspid);
214 buf->msg_lrpid = REAL_TO_VIRTUAL_PID(buf->msg_lrpid);
215 }
216 DMTCP_PLUGIN_ENABLE_CKPT();
217 return ret;
218 }
219
220 extern "C"
221 int clock_getcpuclockid(pid_t pid, clockid_t *clock_id)
222 {
223 DMTCP_PLUGIN_DISABLE_CKPT();
224 pid_t realPid = VIRTUAL_TO_REAL_PID(pid);
225 int ret = _real_clock_getcpuclockid(realPid, clock_id);
226 DMTCP_PLUGIN_ENABLE_CKPT();
227 return ret;
228 }
229
230 extern "C" int timer_create(clockid_t clockid,
231 struct sigevent *sevp,
232 timer_t *timerid)
233 {
234 if (sevp != NULL && (sevp->sigev_notify | SIGEV_THREAD_ID)) {
235 DMTCP_PLUGIN_DISABLE_CKPT();
236 pid_t virtPid = sevp->_sigev_un._tid;
237 sevp->_sigev_un._tid = VIRTUAL_TO_REAL_PID(virtPid);
238 int ret = _real_timer_create(clockid, sevp, timerid);
239 sevp->_sigev_un._tid = virtPid;
240 DMTCP_PLUGIN_ENABLE_CKPT();
241 return ret;
242 }
243 return _real_timer_create(clockid, sevp, timerid);
244 }
245
246
247 #if 0
248 extern "C"
249 int mq_notify(mqd_t mqdes, const struct sigevent *sevp)
250 {
251 struct sigevent n;
252 int ret;
253 DMTCP_PLUGIN_DISABLE_CKPT();
254 if (sevp != NULL) {
255 n = *sevp;
256 n.sigev_notify_thread_id = VIRTUAL_TO_REAL_PID(n.sigev_notify_thread_id);
257 ret = _real_mq_notify(mqdes, &n);
258 } else {
259 ret = _real_mq_notify(mqdes, sevp);
260 }
261 DMTCP_PLUGIN_ENABLE_CKPT();
262 return ret;
263 }
264 #endif
265
266 extern "C" int __clone (int (*fn) (void *arg), void *child_stack, int flags, void *arg, int *parent_tidptr, struct user_desc *newtls, int *child_tidptr);
267
268 #define SYSCALL_VA_START() \
269 va_list ap; \
270 va_start(ap, sys_num)
271
272 #define SYSCALL_VA_END() \
273 va_end(ap)
274
275 #define SYSCALL_GET_ARG(type,arg) type arg = va_arg(ap, type)
276
277 #define SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2) \
278 SYSCALL_GET_ARG(type1,arg1); \
279 SYSCALL_GET_ARG(type2,arg2)
280
281 #define SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3) \
282 SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2); \
283 SYSCALL_GET_ARG(type3,arg3)
284
285 #define SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
286 SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3); \
287 SYSCALL_GET_ARG(type4,arg4)
288
289 #define SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
290 type5,arg5) \
291 SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4); \
292 SYSCALL_GET_ARG(type5,arg5)
293
294 #define SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
295 type5,arg5,type6,arg6) \
296 SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
297 type5,arg5); \
298 SYSCALL_GET_ARG(type6,arg6)
299
300 #define SYSCALL_GET_ARGS_7(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
301 type5,arg5,type6,arg6,type7,arg7) \
302 SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
303 type5,arg5,type6,arg6); \
304 SYSCALL_GET_ARG(type7,arg7)
305
306 /* Comments by Gene:
307 * Here, syscall is the wrapper, and the call to syscall would be _real_syscall
308 * We would add a special case for SYS_gettid, while all others default as below
309 * It depends on the idea that arguments are stored in registers, whose
310 * natural size is: sizeof(void*)
311 * So, we pass six arguments to syscall, and it will ignore any extra arguments
312 * I believe that all Linux system calls have no more than 7 args.
313 * clone() is an example of one with 7 arguments.
314 * If we discover system calls for which the 7 args strategy doesn't work,
315 * we can special case them.
316 *
317 * XXX: DO NOT USE JTRACE/JNOTE/JASSERT in this function; even better, do not
318 * use any STL here. (--Kapil)
319 */
320 extern "C" long syscall(long sys_num, ...)
321 {
322 long ret;
323 va_list ap;
324
325 va_start(ap, sys_num);
326
327 switch (sys_num) {
328 case SYS_gettid:
329 {
330 ret = dmtcp_gettid();
331 break;
332 }
333 case SYS_tkill:
334 {
335 SYSCALL_GET_ARGS_2(int, tid, int, sig);
336 ret = dmtcp_tkill(tid, sig);
337 break;
338 }
339 case SYS_tgkill:
340 {
341 SYSCALL_GET_ARGS_3(int, tgid, int, tid, int, sig);
342 ret = dmtcp_tgkill(tgid, tid, sig);
343 break;
344 }
345
346 case SYS_getpid:
347 {
348 ret = getpid();
349 break;
350 }
351 case SYS_getppid:
352 {
353 ret = getppid();
354 break;
355 }
356
357 case SYS_getpgrp:
358 {
359 ret = getpgrp();
360 break;
361 }
362
363 case SYS_getpgid:
364 {
365 SYSCALL_GET_ARG(pid_t,pid);
366 ret = getpgid(pid);
367 break;
368 }
369 case SYS_setpgid:
370 {
371 SYSCALL_GET_ARGS_2(pid_t,pid,pid_t,pgid);
372 ret = setpgid(pid, pgid);
373 break;
374 }
375
376 case SYS_getsid:
377 {
378 SYSCALL_GET_ARG(pid_t,pid);
379 ret = getsid(pid);
380 break;
381 }
382 case SYS_setsid:
383 {
384 ret = setsid();
385 break;
386 }
387
388 case SYS_kill:
389 {
390 SYSCALL_GET_ARGS_2(pid_t,pid,int,sig);
391 ret = kill(pid, sig);
392 break;
393 }
394
395 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9))
396 case SYS_waitid:
397 {
398 //SYSCALL_GET_ARGS_4(idtype_t,idtype,id_t,id,siginfo_t*,infop,int,options);
399 SYSCALL_GET_ARGS_4(int,idtype,id_t,id,siginfo_t*,infop,int,options);
400 ret = waitid((idtype_t)idtype, id, infop, options);
401 break;
402 }
403 #endif
404 case SYS_wait4:
405 {
406 SYSCALL_GET_ARGS_4(pid_t,pid,__WAIT_STATUS,status,int,options,
407 struct rusage*,rusage);
408 ret = wait4(pid, status, options, rusage);
409 break;
410 }
411 #ifdef __i386__
412 case SYS_waitpid:
413 {
414 SYSCALL_GET_ARGS_3(pid_t,pid,int*,status,int,options);
415 ret = waitpid(pid, status, options);
416 break;
417 }
418 #endif
419
420 case SYS_setgid:
421 {
422 SYSCALL_GET_ARG(gid_t,gid);
423 ret = setgid(gid);
424 break;
425 }
426 case SYS_setuid:
427 {
428 SYSCALL_GET_ARG(uid_t,uid);
429 ret = setuid(uid);
430 break;
431 }
432
433 #ifndef DISABLE_SYS_V_IPC
434 # ifdef __x86_64__
435 // These SYS_xxx are only defined for 64-bit Linux
436 case SYS_shmget:
437 {
438 SYSCALL_GET_ARGS_3(key_t,key,size_t,size,int,shmflg);
439 ret = shmget(key, size, shmflg);
440 break;
441 }
442 case SYS_shmat:
443 {
444 SYSCALL_GET_ARGS_3(int,shmid,const void*,shmaddr,int,shmflg);
445 ret = (unsigned long) shmat(shmid, shmaddr, shmflg);
446 break;
447 }
448 case SYS_shmdt:
449 {
450 SYSCALL_GET_ARG(const void*,shmaddr);
451 ret = shmdt(shmaddr);
452 break;
453 }
454 case SYS_shmctl:
455 {
456 SYSCALL_GET_ARGS_3(int,shmid,int,cmd,struct shmid_ds*,buf);
457 ret = shmctl(shmid, cmd, buf);
458 break;
459 }
460 # endif
461 #endif
462
463 default:
464 {
465 SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4,
466 void*, arg5, void*, arg6, void*, arg7);
467 ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
468 break;
469 }
470 }
471 va_end(ap);
472 return ret;
473 }