extern "C" int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, unsigned int flags) { WRAPPER_HEADER(int, getnameinfo, _real_getnameinfo, sa, salen, host, hostlen, serv, servlen, flags); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(getnameinfo); if (retval == 0 && host != NULL) { strncpy(host, GET_FIELD(my_entry, getnameinfo, ret_host), hostlen); } if (retval == 0 && host != NULL) { strncpy(serv, GET_FIELD(my_entry, getnameinfo, ret_serv), servlen); } WRAPPER_REPLAY_END(getnameinfo); } else if (SYNC_IS_RECORD) { isOptionalEvent = true; retval = _real_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); isOptionalEvent = false; if (retval == 0 && host != NULL) { strncpy(GET_FIELD(my_entry, getnameinfo, ret_host), host, hostlen); } if (retval == 0 && host != NULL) { strncpy(GET_FIELD(my_entry, getnameinfo, ret_serv), serv, servlen); } WRAPPER_LOG_WRITE_ENTRY(my_entry); } return retval; }
extern "C" int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result) { WRAPPER_HEADER(int, getgrgid_r, _real_getgrgid_r, gid, grp, buf, buflen, result); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(getgrgid_r); if (retval == 0 && GET_FIELD(my_entry, getgrgid_r, ret_result) != NULL) { *grp = GET_FIELD(my_entry, getgrgid_r, ret_grp); WRAPPER_REPLAY_READ_FROM_READ_LOG(getgrgid_r, buf, buflen); } *result = GET_FIELD(my_entry, getgrgid_r, ret_result); WRAPPER_REPLAY_END(getgrgid_r); } else if (SYNC_IS_RECORD) { isOptionalEvent = true; retval = _real_getgrgid_r(gid, grp, buf, buflen, result); isOptionalEvent = false; if (retval == 0 && result != NULL) { SET_FIELD2(my_entry, getgrgid_r, ret_grp, *grp); WRAPPER_LOG_WRITE_INTO_READ_LOG(getgrgid_r, buf, buflen); } SET_FIELD2(my_entry, getgrgid_r, ret_result, *result); WRAPPER_LOG_WRITE_ENTRY(my_entry); } return retval; }
extern "C" int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result) { WRAPPER_HEADER(int, getpwuid_r, _real_getpwuid_r, uid, pwd, buf, buflen, result); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(getpwuid_r); if (retval == 0 && GET_FIELD(my_entry, getpwuid_r, ret_result) != NULL) { *pwd = GET_FIELD(my_entry, getpwuid_r, ret_pwd); WRAPPER_REPLAY_READ_FROM_READ_LOG(getpwuid_r, buf, buflen); } *result = GET_FIELD(my_entry, getpwuid_r, ret_result); WRAPPER_REPLAY_END(getpwuid_r); } else if (SYNC_IS_RECORD) { isOptionalEvent = true; retval = _real_getpwuid_r(uid, pwd, buf, buflen, result); isOptionalEvent = false; if (retval == 0 && result != NULL) { SET_FIELD2(my_entry, getpwuid_r, ret_pwd, *pwd); WRAPPER_LOG_WRITE_INTO_READ_LOG(getpwuid_r, buf, buflen); } SET_FIELD2(my_entry, getpwuid_r, ret_result, *result); WRAPPER_LOG_WRITE_ENTRY(my_entry); } return retval; }
extern "C" int pthread_join (pthread_t thread, void **value_ptr) { /* Reap Existing Threads */ //dmtcp::ThreadInfo::reapThreads(); /* We change things up a bit here. Since we don't allow the user's pthread_join() to have an effect, we don't call the mtcp "delete_thread_on_pthread_join()" function here unless we decide not to synchronize this call to pthread_join(). We DO need to call it from the thread reaper reapThread(), however, which is in pthreadwrappers.cpp. */ //if (!dmtcp::ThreadInfo::isUserJoinable(thread)) { //return EINVAL; //} void *return_addr = GET_RETURN_ADDRESS(); if (!shouldSynchronize(return_addr)) { int retval = _real_pthread_join(thread, value_ptr); if (retval == 0) { dmtcp::ThreadInfo::reapThread(thread); } return retval; } int retval = 0; log_entry_t my_entry = create_pthread_join_entry(my_clone_id, pthread_join_event, thread, value_ptr); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(pthread_join); int saved_retval = (long) RETVAL(my_entry, pthread_join); WRAPPER_REPLAY_END(pthread_join); retval = _real_pthread_join(thread, value_ptr); JASSERT(retval == saved_retval); if (value_ptr != NULL) { JASSERT(*value_ptr == GET_FIELD(my_entry, pthread_join, ret_value_ptr)); } } else if (SYNC_IS_RECORD) { WRAPPER_LOG_RESERVE_SLOT(pthread_join); retval = _real_pthread_join(thread, value_ptr); if (value_ptr != NULL) { SET_FIELD2(my_entry, pthread_join, ret_value_ptr, *value_ptr); } WRAPPER_LOG_UPDATE_ENTRY(pthread_join); } return retval; }
extern "C" int munmap(void *addr, size_t length) { MALLOC_FAMILY_WRAPPER_HEADER_TYPED(int, munmap, addr, length); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(munmap); _real_pthread_mutex_lock(&allocation_lock); retval = _real_munmap (addr, length); JASSERT (retval == (int)(unsigned long)GET_COMMON(my_entry, retval)); _real_pthread_mutex_unlock(&allocation_lock); WRAPPER_REPLAY_END(munmap); } else if (SYNC_IS_RECORD) { _real_pthread_mutex_lock(&mmap_lock); retval = _real_munmap (addr, length); WRAPPER_LOG_WRITE_ENTRY(my_entry); _real_pthread_mutex_unlock(&mmap_lock); } return retval; }
extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp) { WRAPPER_HEADER(int, clock_gettime, _real_clock_gettime, clk_id, tp); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(clock_gettime); if (retval == 0 && tp != NULL) { *tp = GET_FIELD(my_entry, clock_gettime, ret_tp); } WRAPPER_REPLAY_END(clock_gettime); } else if (SYNC_IS_RECORD) { retval = _real_clock_gettime(clk_id, tp); if (retval == 0 && tp != NULL) { SET_FIELD2(my_entry, clock_gettime, ret_tp, *tp); } WRAPPER_LOG_WRITE_ENTRY(clock_gettime); } return retval; }
extern "C" int clock_getres(clockid_t clk_id, struct timespec *res) { WRAPPER_HEADER(int, clock_getres, _real_clock_getres, clk_id, res); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(clock_getres); if (retval == 0 && res != NULL) { *res = GET_FIELD(my_entry, clock_getres, ret_res); } WRAPPER_REPLAY_END(clock_getres); } else if (SYNC_IS_RECORD) { retval = _real_clock_getres(clk_id, res); if (retval == 0 && res != NULL) { SET_FIELD2(my_entry, clock_getres, ret_res, *res); } WRAPPER_LOG_WRITE_ENTRY(clock_getres); } return retval; }
extern "C" time_t time(time_t *tloc) { WRAPPER_HEADER(time_t, time, _real_time, tloc); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(time); if (retval != (time_t) -1 && tloc != NULL) { *tloc = GET_FIELD(my_entry, time, ret_tloc); } WRAPPER_REPLAY_END(time); } else if (SYNC_IS_RECORD) { retval = _real_time(tloc); if (tloc != NULL) { SET_FIELD2(my_entry, time, ret_tloc, *tloc); } WRAPPER_LOG_WRITE_ENTRY(time); } return retval; }
extern "C" int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { WRAPPER_EXECUTION_DISABLE_CKPT(); WRAPPER_HEADER_CKPT_DISABLED(int, getpeername, _real_getpeername, sockfd, addr, addrlen); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(getpeername); if (retval != -1) { *addr = GET_FIELD(my_entry, getpeername, ret_addr); *addrlen = GET_FIELD(my_entry, getpeername, ret_addrlen); } WRAPPER_REPLAY_END(getpeername); } else if (SYNC_IS_RECORD) { retval = _real_getpeername(sockfd, addr, addrlen); if (retval != -1) { SET_FIELD2(my_entry, getpeername, ret_addr, *addr); SET_FIELD2(my_entry, getpeername, ret_addrlen, *addrlen); } WRAPPER_LOG_WRITE_ENTRY(my_entry); } WRAPPER_EXECUTION_ENABLE_CKPT(); return retval; }
extern "C" int gettimeofday(struct timeval *tv, struct timezone *tz) { WRAPPER_HEADER(int, gettimeofday, _real_gettimeofday, tv, tz); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(gettimeofday); if (retval == 0 && tv != NULL) { *tv = GET_FIELD(my_entry, gettimeofday, ret_tv); } if (retval == 0 && tz != NULL) { *tz = GET_FIELD(my_entry, gettimeofday, ret_tz); } WRAPPER_REPLAY_END(gettimeofday); } else if (SYNC_IS_RECORD) { retval = _real_gettimeofday(tv, tz); if (retval == 0 && tv != NULL) { SET_FIELD2(my_entry, gettimeofday, ret_tv, *tv); } if (retval == 0 && tz != NULL) { SET_FIELD2(my_entry, gettimeofday, ret_tz, *tz); } WRAPPER_LOG_WRITE_ENTRY(gettimeofday); } return retval; }
extern "C" int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { struct addrinfo_extended addrinfo_res[ADDRINFO_MAX_RES]; struct addrinfo *rp; int numResults = 0; WRAPPER_HEADER(int, getaddrinfo, _real_getaddrinfo, node, service, hints, res); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(getaddrinfo); if (retval == 0) { *res = GET_FIELD(my_entry, getaddrinfo, ret_res); numResults = GET_FIELD(my_entry, getaddrinfo, num_res); WRAPPER_REPLAY_READ_FROM_READ_LOG(getaddrinfo, (void*) addrinfo_res, (numResults * sizeof (struct addrinfo_extended))); for (int i = 0; i < numResults; i++) { struct addrinfo_extended *ext_info = &addrinfo_res[i]; struct addrinfo *_addrinfo = &(addrinfo_res[i]._addrinfo); struct sockaddr *_sockaddr = &(addrinfo_res[i]._sockaddr); memcpy(ext_info->_addrinfo_p, _addrinfo, sizeof(struct addrinfo)); memcpy(_addrinfo->ai_addr, _sockaddr, _addrinfo->ai_addrlen); if (_addrinfo->ai_canonname != NULL) { strncpy(_addrinfo->ai_canonname, ext_info->canonname, sizeof(ext_info->canonname)); } } } WRAPPER_REPLAY_END(getaddrinfo); } else if (SYNC_IS_RECORD) { isOptionalEvent = true; retval = _real_getaddrinfo(node, service, hints, res); isOptionalEvent = false; if (retval == 0) { SET_FIELD2(my_entry, getaddrinfo, ret_res, *res); for (rp = *res; rp != NULL; rp = rp->ai_next) { JASSERT(numResults < ADDRINFO_MAX_RES); struct addrinfo_extended *ext_info = &addrinfo_res[numResults]; struct addrinfo *_addrinfo = &(addrinfo_res[numResults]._addrinfo); struct sockaddr *_sockaddr = &(addrinfo_res[numResults]._sockaddr); ext_info->_addrinfo_p = rp; memcpy(_addrinfo, rp, sizeof (struct addrinfo)); memcpy(_sockaddr, rp->ai_addr, rp->ai_addrlen); if (rp->ai_canonname != NULL) { strncpy(ext_info->canonname, rp->ai_canonname, sizeof(ext_info->canonname)); } numResults++; } WRAPPER_LOG_WRITE_INTO_READ_LOG(getaddrinfo, (void*) addrinfo_res, (numResults * sizeof (struct addrinfo_extended))); } SET_FIELD2(my_entry, getaddrinfo, num_res, numResults); WRAPPER_LOG_WRITE_ENTRY(my_entry); } return retval; }
/* Performs the _real version with log and replay. Does NOT check shouldSynchronize() and shouldn't be called directly unless you know what you're doing. */ static int internal_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg) { int retval = 0, was_detached = 0; pthread_attr_t the_attr; size_t stack_size; void *stack_addr; struct create_arg *createArg = (struct create_arg*) JALLOC_HELPER_MALLOC(sizeof(*createArg)); createArg->fn = start_routine; createArg->thread_arg = arg; if (attr != NULL) { pthread_attr_getstack(attr, &createArg->userStack, &stack_size); pthread_attr_getdetachstate(attr, &createArg->userDetachState); } else { createArg->userStack = NULL; createArg->userDetachState = PTHREAD_CREATE_JOINABLE; } log_entry_t my_entry = create_pthread_create_entry(my_clone_id, pthread_create_event, thread, attr, start_routine, arg); if (SYNC_IS_REPLAY) { WRAPPER_REPLAY_START(pthread_create); stack_addr = (void *)GET_FIELD(my_entry, pthread_create, stack_addr); stack_size = GET_FIELD(my_entry, pthread_create, stack_size); dmtcp::ThreadInfo::prePthreadCreate(); WRAPPER_REPLAY_END(pthread_create); // Register a new thread with ThreadInfo. pthread_t newPthreadId = GET_FIELD(my_entry, pthread_create, ret_thread); // Set up thread stacks to how they were at record time. pthread_attr_init(&the_attr); setupThreadStack(&the_attr, attr, stack_size); // Never let the user create a detached thread: disableDetachState(&the_attr); createArg->attr = the_attr; retval = _real_pthread_create(thread, &the_attr, start_wrapper, (void *)createArg); pthread_attr_destroy(&the_attr); } else if (SYNC_IS_RECORD) { WRAPPER_LOG_RESERVE_SLOT(pthread_create); dmtcp::ThreadInfo::prePthreadCreate(); pthread_attr_init(&the_attr); // Possibly create a thread stack if the user has not provided one: setupThreadStack(&the_attr, attr, 0); // Never let the user create a detached thread: disableDetachState(&the_attr); createArg->attr = the_attr; // MTCP may call jalib::malloc to allocate space for thread struct. dmtcp::ThreadInfo::setOptionalEvent(); retval = _real_pthread_create(thread, &the_attr, start_wrapper, (void *)createArg); dmtcp::ThreadInfo::unsetOptionalEvent(); SET_RETVAL_ERRNO(my_entry, pthread_create, retval, errno); // Log whatever stack we ended up using: pthread_attr_getstack(&the_attr, &stack_addr, &stack_size); pthread_attr_destroy(&the_attr); SET_FIELD(my_entry, pthread_create, stack_addr); SET_FIELD(my_entry, pthread_create, stack_size); SET_FIELD2(my_entry, pthread_create, ret_thread, *thread); // Log annotation on the fly. WRAPPER_LOG_UPDATE_ENTRY(pthread_create); } if (retval != 0) { dmtcp::ThreadInfo::postPthreadCreate(); } return retval; }