// gettid / tkill / tgkill are not defined in libc. // So, this is needed even if there is no PID_VIRTUALIZATION. pid_t _real_gettid(void){ #ifdef PID_VIRTUALIZATION // IS THIS LIKE ORIGINAL? REAL_FUNC_PASSTHROUGH_PID_T ( _real_syscall(SYS_gettid) ); #else REAL_FUNC_PASSTHROUGH_PID_T ( syscall(SYS_gettid) ); #endif }
extern "C" pid_t fork() { if (isPerformingCkptRestart()) { return _real_syscall(SYS_fork); } /* Acquire the wrapperExeution lock to prevent checkpoint to happen while * processing this system call. */ WRAPPER_EXECUTION_GET_EXCL_LOCK(); dmtcp::DmtcpWorker::processEvent(DMTCP_EVENT_PRE_FORK, NULL); /* Little bit cheating here: child_time should be same for both parent and * child, thus we compute it before forking the child. */ child_time = time(NULL); long host = dmtcp::UniquePid::ThisProcess().hostid(); dmtcp::UniquePid parent = dmtcp::UniquePid::ThisProcess(); dmtcp::string child_name = jalib::Filesystem::GetProgramName() + "_(forked)"; coordinatorAPI.createNewConnectionBeforeFork(child_name); dmtcp::Util::setVirtualPidEnvVar(coordinatorAPI.virtualPid(), getpid()); //Enable the pthread_atfork child call pthread_atfork_enabled = true; pid_t childPid = _real_fork(); if (childPid == -1) { } else if (childPid == 0) { /* child process */ /* NOTE: Any work that needs to be done for the newly created child * should be put into pthread_atfork_child() function. That function is * hooked to the libc:fork() and will be called right after the new * process is created and before the fork() returns. * * pthread_atfork_child is registered by calling pthread_atfork() from * within the DmtcpWorker constructor to make sure that this is the first * registered handle. */ dmtcp::UniquePid child = dmtcp::UniquePid(host, getpid(), child_time); JTRACE("fork() done [CHILD]") (child) (parent); dmtcp::initializeMtcpEngine(); } else if (childPid > 0) { /* Parent Process */ dmtcp::UniquePid child = dmtcp::UniquePid(host, childPid, child_time); dmtcp::ProcessInfo::instance().insertChild(childPid, child); JTRACE("fork()ed [PARENT] done") (child);; } pthread_atfork_enabled = false; if (childPid != 0) { dmtcp::Util::setVirtualPidEnvVar(getpid(), getppid()); coordinatorAPI.closeConnection(); WRAPPER_EXECUTION_RELEASE_EXCL_LOCK(); } return childPid; }
extern "C" long int syscall(long int sys_num, ... ) { long int ret; va_list ap; va_start(ap, sys_num); switch ( sys_num ) { case SYS_mmap: { SYSCALL_GET_ARGS_6(void*, addr, size_t, length, int, prot, int, flags, int, fd, off_t, offset); ret = (long int) fred_mmap(addr, length, prot, flags, fd, offset); break; } case SYS_mremap: { SYSCALL_GET_ARGS_5(void*, old_addr, size_t, old_size, size_t, new_size, int, flags, void*, new_addr); ret = (long int) fred_mremap(old_addr, old_size, new_size, flags, new_addr); break; } case SYS_munmap: { SYSCALL_GET_ARGS_2(void*, addr, size_t, length); ret = fred_munmap(addr, length); break; } default: { SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4, void*, arg5, void*, arg6, void*, arg7); ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7); break; } } va_end(ap); return ret; }
LIB_PRIVATE pid_t _real_getppid(void){ // libc caches ppid of the process and hence after restart, libc:getppid() // returns the pre-ckpt value. return (pid_t) _real_syscall(SYS_getppid); }
LIB_PRIVATE int _real_tgkill(int tgid, int tid, int sig) { // No glibc wrapper for tgkill, although even if it had one, we would have // the issues similar to getpid/getppid(). return (int) _real_syscall(SYS_tgkill, tgid, tid, sig); }
// gettid / tkill / tgkill are not defined in libc. // So, this is needed even if there is no PID_VIRTUALIZATION LIB_PRIVATE pid_t _real_gettid(void){ // No glibc wrapper for gettid, although even if it had one, we would have // the issues similar to getpid/getppid(). return (pid_t) _real_syscall(SYS_gettid); }
/* Comments by Gene: * Here, syscall is the wrapper, and the call to syscall would be _real_syscall * We would add a special case for SYS_gettid, while all others default as below * It depends on the idea that arguments are stored in registers, whose * natural size is: sizeof(void*) * So, we pass six arguments to syscall, and it will ignore any extra arguments * I believe that all Linux system calls have no more than 7 args. * clone() is an example of one with 7 arguments. * If we discover system calls for which the 7 args strategy doesn't work, * we can special case them. * * XXX: DO NOT USE JTRACE/JNOTE/JASSERT in this function; even better, do not * use any STL here. (--Kapil) */ extern "C" SYSCALL_ARG_RET_TYPE syscall(SYSCALL_ARG_RET_TYPE sys_num, ... ) { long int ret; va_list ap; va_start(ap, sys_num); switch ( sys_num ) { case SYS_clone: { typedef int (*fnc) (void*); SYSCALL_GET_ARGS_7(fnc, fn, void*, child_stack, int, flags, void*, arg, pid_t*, pid, struct user_desc*, tls, pid_t*, ctid); ret = __clone(fn, child_stack, flags, arg, pid, tls, ctid); break; } case SYS_execve: { SYSCALL_GET_ARGS_3(const char*,filename,char* const *,argv,char* const *,envp); ret = execve(filename,argv,envp); break; } case SYS_fork: { ret = fork(); break; } case SYS_exit: { SYSCALL_GET_ARG(int,status); exit(status); break; } case SYS_open: { SYSCALL_GET_ARGS_3(const char*,pathname,int,flags,mode_t,mode); ret = open(pathname, flags, mode); break; } case SYS_close: { SYSCALL_GET_ARG(int,fd); ret = close(fd); break; } case SYS_rt_sigaction: { SYSCALL_GET_ARGS_3(int,signum,const struct sigaction*,act,struct sigaction*,oldact); ret = sigaction(signum, act, oldact); break; } case SYS_rt_sigprocmask: { SYSCALL_GET_ARGS_3(int,how,const sigset_t*,set,sigset_t*,oldset); ret = sigprocmask(how, set, oldset); break; } case SYS_rt_sigtimedwait: { SYSCALL_GET_ARGS_3(const sigset_t*,set,siginfo_t*,info, const struct timespec*, timeout); ret = sigtimedwait(set, info, timeout); break; } #ifdef __i386__ case SYS_sigaction: { SYSCALL_GET_ARGS_3(int,signum,const struct sigaction*,act,struct sigaction*,oldact); ret = sigaction(signum, act, oldact); break; } case SYS_signal: { typedef void (*sighandler_t)(int); SYSCALL_GET_ARGS_2(int,signum,sighandler_t,handler); // Cast needed: signal returns sighandler_t ret = (long int)signal(signum, handler); break; } case SYS_sigprocmask: { SYSCALL_GET_ARGS_3(int,how,const sigset_t*,set,sigset_t*,oldset); ret = sigprocmask(how, set, oldset); break; } #endif #ifdef __x86_64__ // These SYS_xxx are only defined for 64-bit Linux case SYS_socket: { SYSCALL_GET_ARGS_3(int,domain,int,type,int,protocol); ret = socket(domain,type,protocol); break; } case SYS_connect: { SYSCALL_GET_ARGS_3(int,sockfd,const struct sockaddr*,addr,socklen_t,addrlen); ret = connect(sockfd, addr, addrlen); break; } case SYS_bind: { SYSCALL_GET_ARGS_3(int,sockfd,const struct sockaddr*,addr,socklen_t,addrlen); ret = bind(sockfd,addr,addrlen); break; } case SYS_listen: { SYSCALL_GET_ARGS_2(int,sockfd,int,backlog); ret = listen(sockfd,backlog); break; } case SYS_accept: { SYSCALL_GET_ARGS_3(int,sockfd,struct sockaddr*,addr,socklen_t*,addrlen); ret = accept(sockfd, addr, addrlen); break; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) && __GLIBC_PREREQ(2,10) case SYS_accept4: { SYSCALL_GET_ARGS_4(int,sockfd,struct sockaddr*,addr,socklen_t*,addrlen,int,flags); ret = accept4(sockfd, addr, addrlen, flags); break; } #endif case SYS_setsockopt: { SYSCALL_GET_ARGS_5(int,s,int,level,int,optname,const void*,optval,socklen_t,optlen); ret = setsockopt(s, level, optname, optval, optlen); break; } case SYS_socketpair: { SYSCALL_GET_ARGS_4(int,d,int,type,int,protocol,int*,sv); ret = socketpair(d,type,protocol,sv); break; } #endif case SYS_pipe: { SYSCALL_GET_ARG(int*,fds); ret = pipe(fds); break; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) && __GLIBC_PREREQ(2,9) case SYS_pipe2: { SYSCALL_GET_ARGS_2(int*,fds,int,flags); ret = pipe2(fds, flags); break; } #endif case SYS_setsid: { ret = setsid(); break; } #ifndef DISABLE_SYS_V_IPC # ifdef __x86_64__ // These SYS_xxx are only defined for 64-bit Linux case SYS_shmget: { SYSCALL_GET_ARGS_3(key_t,key,size_t,size,int,shmflg); ret = shmget(key, size, shmflg); break; } case SYS_shmat: { SYSCALL_GET_ARGS_3(int,shmid,const void*,shmaddr,int,shmflg); ret = (unsigned long) shmat(shmid, shmaddr, shmflg); break; } case SYS_shmdt: { SYSCALL_GET_ARG(const void*,shmaddr); ret = shmdt(shmaddr); break; } case SYS_shmctl: { SYSCALL_GET_ARGS_3(int,shmid,int,cmd,struct shmid_ds*,buf); ret = shmctl(shmid, cmd, buf); break; } # endif #endif case SYS_poll: { SYSCALL_GET_ARGS_3(struct pollfd *,fds,nfds_t,nfds,int,timeout); ret = poll(fds, nfds, timeout); break; } case SYS_epoll_create: { SYSCALL_GET_ARG(int,size); ret = epoll_create(size); break; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) && __GLIBC_PREREQ(2,4) case SYS_inotify_init: { ret = inotify_init(); break; } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) && __GLIBC_PREREQ(2,8) case SYS_signalfd: { SYSCALL_GET_ARGS_3(int,fd,sigset_t *,mask,int,flags); ret = signalfd(fd, mask, flags); break; } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && __GLIBC_PREREQ(2,8) case SYS_signalfd4: { SYSCALL_GET_ARGS_3(int,fd,sigset_t *,mask,int,flags); ret = signalfd(fd, mask, flags); break; } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) && __GLIBC_PREREQ(2,8) case SYS_eventfd: { SYSCALL_GET_ARGS_2(unsigned int,initval,int,flags); ret = eventfd(initval, flags); break; } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && __GLIBC_PREREQ(2,8) case SYS_eventfd2: { SYSCALL_GET_ARGS_2(unsigned int,initval,int,flags); ret = eventfd(initval, flags); break; } #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && __GLIBC_PREREQ(2,9) case SYS_epoll_create1: { SYSCALL_GET_ARG(int,flags); ret = epoll_create(flags); break; } case SYS_inotify_init1: { SYSCALL_GET_ARG(int,flags); ret = inotify_init1(flags); break; } #endif default: { SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4, void*, arg5, void*, arg6, void*, arg7); ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7); break; } } va_end(ap); return ret; }
LIB_PRIVATE int dmtcp_tgkill(int tgid, int tid, int sig) { return _real_syscall(SYS_tgkill, tgid, tid, sig); }
// gettid / tkill / tgkill are not defined in libc. LIB_PRIVATE pid_t dmtcp_gettid() { return _real_syscall(SYS_gettid); }
LIB_PRIVATE int _real_tgkill(int tgid, int tid, int sig) { return (int) _real_syscall(SYS_tgkill, tgid, tid, sig); }
/* Comments by Gene: * Here, syscall is the wrapper, and the call to syscall would be _real_syscall * We would add a special case for SYS_gettid, while all others default as below * It depends on the idea that arguments are stored in registers, whose * natural size is: sizeof(void*) * So, we pass six arguments to syscall, and it will ignore any extra arguments * I believe that all Linux system calls have no more than 7 args. * clone() is an example of one with 7 arguments. * If we discover system calls for which the 7 args strategy doesn't work, * we can special case them. * * XXX: DO NOT USE JTRACE/JNOTE/JASSERT in this function; even better, do not * use any STL here. (--Kapil) */ extern "C" long int syscall(long int sys_num, ... ) { long int ret; va_list ap; va_start(ap, sys_num); switch ( sys_num ) { case SYS_gettid: { ret = gettid(); break; } case SYS_tkill: { SYSCALL_GET_ARGS_2(int, tid, int, sig); ret = tkill(tid, sig); break; } case SYS_tgkill: { SYSCALL_GET_ARGS_3(int, tgid, int, tid, int, sig); ret = tgkill(tgid, tid, sig); break; } case SYS_getpid: { ret = getpid(); break; } case SYS_getppid: { ret = getppid(); break; } case SYS_getpgrp: { ret = getpgrp(); break; } case SYS_getpgid: { SYSCALL_GET_ARG(pid_t,pid); ret = getpgid(pid); break; } case SYS_setpgid: { SYSCALL_GET_ARGS_2(pid_t,pid,pid_t,pgid); ret = setpgid(pid, pgid); break; } case SYS_getsid: { SYSCALL_GET_ARG(pid_t,pid); ret = getsid(pid); break; } case SYS_setsid: { ret = setsid(); break; } case SYS_kill: { SYSCALL_GET_ARGS_2(pid_t,pid,int,sig); ret = kill(pid, sig); break; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)) case SYS_waitid: { //SYSCALL_GET_ARGS_4(idtype_t,idtype,id_t,id,siginfo_t*,infop,int,options); SYSCALL_GET_ARGS_4(int,idtype,id_t,id,siginfo_t*,infop,int,options); ret = waitid((idtype_t)idtype, id, infop, options); break; } #endif case SYS_wait4: { SYSCALL_GET_ARGS_4(pid_t,pid,__WAIT_STATUS,status,int,options, struct rusage*,rusage); ret = wait4(pid, status, options, rusage); break; } #ifdef __i386__ case SYS_waitpid: { SYSCALL_GET_ARGS_3(pid_t,pid,int*,status,int,options); ret = waitpid(pid, status, options); break; } #endif case SYS_setgid: { SYSCALL_GET_ARG(gid_t,gid); ret = setgid(gid); break; } case SYS_setuid: { SYSCALL_GET_ARG(uid_t,uid); ret = setuid(uid); break; } #ifndef DISABLE_SYS_V_IPC # ifdef __x86_64__ // These SYS_xxx are only defined for 64-bit Linux case SYS_shmget: { SYSCALL_GET_ARGS_3(key_t,key,size_t,size,int,shmflg); ret = shmget(key, size, shmflg); break; } case SYS_shmat: { SYSCALL_GET_ARGS_3(int,shmid,const void*,shmaddr,int,shmflg); ret = (unsigned long) shmat(shmid, shmaddr, shmflg); break; } case SYS_shmdt: { SYSCALL_GET_ARG(const void*,shmaddr); ret = shmdt(shmaddr); break; } case SYS_shmctl: { SYSCALL_GET_ARGS_3(int,shmid,int,cmd,struct shmid_ds*,buf); ret = shmctl(shmid, cmd, buf); break; } # endif #endif default: { SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4, void*, arg5, void*, arg6, void*, arg7); ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7); break; } } va_end(ap); return ret; }