/* Notify the listener that the client has finished sending a message, and * transfer all details for handling the response to it. Blocking. */ static bool enqueue_EXPECT_message_to_listener(bus *b, boxed_msg *box) { /* Notify listener that it should expect a response to a * successfully sent message. */ BUS_LOG_SNPRINTF(b, 3, LOG_SENDER, b->udata, 128, "telling listener to EXPECT sent response, with box %p, seq_id %lld", (void *)box, (long long)box->out_seq_id); if (box->result.status == BUS_SEND_UNDEFINED) { box->result.status = BUS_SEND_REQUEST_COMPLETE; } struct listener *l = Bus_GetListenerForSocket(b, box->fd); for (int retries = 0; retries < SEND_NOTIFY_LISTENER_RETRIES; retries++) { #ifndef TEST uint16_t backpressure = 0; #endif /* If this succeeds, then this thread cannot touch the box anymore. */ if (Listener_ExpectResponse(l, box, &backpressure)) { Bus_BackpressureDelay(b, backpressure, LISTENER_EXPECT_BACKPRESSURE_SHIFT); return true; } else { BUS_LOG_SNPRINTF(b, 5, LOG_SENDER, b->udata, 64, "enqueue_request_sent: failed delivery %d", retries); syscall_poll(NULL, 0, SEND_NOTIFY_LISTENER_RETRY_DELAY); } } /* Timeout, will be treated as a TX error */ return false; }
int io_poll(int64_t *remain, int64_t *timeout) { int to = -1; uint64_t old; uint64_t deadline = timer_mtime; size_t i; int ret; old = timer_mtime; /* There is a timeout, set it */ if(timeout) if(*timeout >= 0LL) { to = (int)(*timeout); deadline = timer_mtime + *timeout + 10; } /* Do the actual poll() */ ret = syscall_poll(io_count ? io_pfds : NULL, io_count, to); /* Update system time */ timer_update(); /* * If a timeout was set then set the timeout pointer * to the remaining time until the poll deadline. */ if(timeout && remain) { *remain = deadline - timer_mtime; if(*remain < 0LL) { if(*remain < -POLL_WARN_DELTA) log(io_log, L_warning, "Timing error: poll() returned too late (diff: %lli)", *remain); *remain = 0; } if(*remain > *timeout) { if(*remain > *timeout + POLL_WARN_DELTA) log(io_log, L_warning, "Timing error: poll() returned too early (diff: %lli)", *remain); *remain = *timeout; } } /* Now set the returned events */ for(i = 0; i < io_count; i++) io_set_revents(io_pfds[i].fd); return ret; }
static bool do_blocking_connection(struct bus *b, SSL *ssl, int fd) { BUS_LOG_SNPRINTF(b, 2, LOG_SOCKET_REGISTERED, b->udata, 128, "SSL_Connect handshake for socket %d", fd); struct pollfd fds[1]; fds[0].fd = fd; fds[0].events = POLLOUT; bool connected = false; size_t elapsed = 0; while (!connected) { int pres = syscall_poll(fds, 1, TIMEOUT_MSEC); BUS_LOG_SNPRINTF(b, 5, LOG_SOCKET_REGISTERED, b->udata, 128, "SSL_Connect handshake for socket %d, poll res %d", fd, pres); if (pres < 0) { if (Util_IsResumableIOError(errno)) { errno = 0; } else { /* */ assert(false); } } else if (pres > 0) { if (fds[0].revents & (POLLOUT | POLLIN)) { int connect_res = SSL_connect(ssl); BUS_LOG_SNPRINTF(b, 5, LOG_SOCKET_REGISTERED, b->udata, 128, "socket %d: connect_res %d", fd, connect_res); if (connect_res == 1) { BUS_LOG_SNPRINTF(b, 5, LOG_SOCKET_REGISTERED, b->udata, 128, "socket %d: successfully connected", fd); connected = true; } else if (connect_res < 0) { int reason = SSL_get_error(ssl, connect_res); switch (reason) { case SSL_ERROR_WANT_WRITE: BUS_LOG(b, 4, LOG_SOCKET_REGISTERED, "WANT_WRITE", b->udata); fds[0].events = POLLOUT; break; case SSL_ERROR_WANT_READ: BUS_LOG(b, 4, LOG_SOCKET_REGISTERED, "WANT_READ", b->udata); fds[0].events = POLLIN; break; case SSL_ERROR_SYSCALL: { if (Util_IsResumableIOError(errno)) { errno = 0; break; } else { unsigned long errval = ERR_get_error(); char ebuf[256]; BUS_LOG_SNPRINTF(b, 1, LOG_SOCKET_REGISTERED, b->udata, 128, "socket %d: ERROR -- %s", fd, ERR_error_string(errval, ebuf)); } } break; default: { unsigned long errval = ERR_get_error(); char ebuf[256]; BUS_LOG_SNPRINTF(b, 1, LOG_SOCKET_REGISTERED, b->udata, 128, "socket %d: ERROR %d -- %s", fd, reason, ERR_error_string(errval, ebuf)); assert(false); } } } else { BUS_LOG_SNPRINTF(b, 5, LOG_SOCKET_REGISTERED, b->udata, 128, "socket %d: unknown state, setting event bask to (POLLIN | POLLOUT)", fd); fds[0].events = (POLLIN | POLLOUT); } } else if (fds[0].revents & POLLHUP) { BUS_LOG_SNPRINTF(b, 1, LOG_SOCKET_REGISTERED, b->udata, 128, "SSL_Connect: HUP on %d", fd); return false; } else if (fds[0].revents & POLLERR) { BUS_LOG_SNPRINTF(b,12, LOG_SOCKET_REGISTERED, b->udata, 128, "SSL_Connect: ERR on %d", fd); return false; } } else { BUS_LOG(b, 4, LOG_SOCKET_REGISTERED, "poll timeout", b->udata); elapsed += TIMEOUT_MSEC; if (elapsed > MAX_TIMEOUT) { BUS_LOG(b, 2, LOG_SOCKET_REGISTERED, "timed out", b->udata); return false; } } } return connected; }
bool BusPoll_OnCompletion(struct bus *b, int fd) { /* POLL in a pipe */ #ifndef TEST struct pollfd fds[1]; #endif fds[0].fd = fd; fds[0].events = POLLIN; for (;;) { BUS_LOG(b, 5, LOG_SENDING_REQUEST, "Polling on completion...tick...", b->udata); #ifdef TEST errno = poll_errno; #endif BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion, polling %d", fd); int res = syscall_poll(fds, 1, -1); BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion for %d, res %d (errno %d)", fd, res, errno); if (res == -1) { if (Util_IsResumableIOError(errno)) { BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion, resumable IO error %d", errno); errno = 0; continue; } else { BUS_LOG_SNPRINTF(b, 1, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion, non-resumable IO error %d", errno); return false; } } else if (res == 1) { uint16_t msec = 0; #ifndef TEST uint8_t read_buf[sizeof(uint8_t) + sizeof(uint16_t)]; #endif if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { BUS_LOG(b, 1, LOG_SENDING_REQUEST, "failed (broken alert pipe)", b->udata); return false; } BUS_LOG(b, 3, LOG_SENDING_REQUEST, "Reading alert pipe...", b->udata); #ifdef TEST errno = read_errno; #endif ssize_t sz = syscall_read(fd, read_buf, sizeof(read_buf)); if (sz == sizeof(read_buf)) { /* Payload: little-endian uint16_t, msec of backpressure. */ assert(read_buf[0] == LISTENER_MSG_TAG); msec = (read_buf[1] << 0) + (read_buf[2] << 8); Bus_BackpressureDelay(b, msec, LISTENER_BACKPRESSURE_SHIFT); BUS_LOG(b, 4, LOG_SENDING_REQUEST, "sent!", b->udata); return true; } else if (sz == -1) { if (Util_IsResumableIOError(errno)) { BUS_LOG_SNPRINTF(b, 5, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion read, resumable IO error %d", errno); errno = 0; continue; } else { BUS_LOG_SNPRINTF(b, 2, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion read, non-resumable IO error %d", errno); errno = 0; return false; } } else { BUS_LOG_SNPRINTF(b, 1, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion bad read size %zd", sz); return false; } } else { /* This should never happen, but I have seen it occur on OSX. * If we log it, reset errno, and continue, it does not appear * to fall into busywaiting by always returning 0. */ BUS_LOG_SNPRINTF(b, 1, LOG_SENDING_REQUEST, b->udata, 64, "poll_on_completion, blocking forever returned %d, errno %d", res, errno); errno = 0; } } }
/** @brief Handles all syscalls of the tracked pid until it does a blocking action. * * Blocking actions are stuff that must be reported to the simulator and which * completion takes time. The most prominent examples are related to sending and * receiving data. * * The tracked pid can run more than one syscall in this function if theses calls * are about the metadata that we maintain in simterpose without exposing them to * simgrid. For example, if you call socket() or accept(), we only have to maintain * our metadata but there is no need to inform the simulator, nor to ask for the * completion time of these things. */ int process_handle(process_descriptor_t * proc) { reg_s arg; pid_t pid = proc->pid; XBT_DEBUG("PROCESS HANDLE MSG"); while (1) { ptrace_get_register(pid, &arg); int ret; XBT_DEBUG("found syscall: [%d] %s (%ld) = %ld, in_syscall = %d", pid, syscall_list[arg.reg_orig], arg.reg_orig, arg.ret, proc->in_syscall); switch (arg.reg_orig) { case SYS_creat: syscall_creat(&arg, proc); break; case SYS_open: XBT_DEBUG("On open"); XBT_DEBUG("Valeur des registres dans l'AS:"); XBT_DEBUG("Valeur de retour %lu", arg.ret); XBT_DEBUG("Valeur des arg %lu %lu %lu %lu %lu %lu", arg.arg[0], arg.arg[1], arg.arg[2], arg.arg[3], arg.arg[4], arg.arg[5]); syscall_open(&arg, proc); break; case SYS_close: syscall_close(&arg, proc); break; case SYS_read: syscall_read(&arg, proc); break; case SYS_write: XBT_DEBUG("On write"); XBT_DEBUG("Valeur des registres dans l'AS:"); XBT_DEBUG("Valeur de retour %lu", arg.ret); XBT_DEBUG("Valeur des arg %lu %lu %lu %lu %lu %lu", arg.arg[0], arg.arg[1], arg.arg[2], arg.arg[3], arg.arg[4], arg.arg[5]); if ((ret = syscall_write(&arg, proc))) return ret; break; case SYS_dup: syscall_dup(&arg, proc); break; case SYS_dup2: syscall_dup2(&arg, proc); break; case SYS_fcntl: syscall_fcntl(&arg, proc); break; case SYS_lseek: syscall_lseek(&arg, proc); break; case SYS_poll: syscall_poll(&arg, proc); break; case SYS_select: syscall_select(&arg, proc); break; case SYS_pipe: syscall_pipe(&arg, proc); case SYS_brk: syscall_brk(&arg, proc); break; case SYS_socket: syscall_socket(&arg, proc); break; case SYS_connect: syscall_connect(&arg, proc); break; case SYS_bind: syscall_bind(&arg, proc); break; case SYS_listen: syscall_listen(&arg, proc); break; case SYS_accept: syscall_accept(&arg, proc); break; #if UINTPTR_MAX == 0xffffffff /* 32-bit architecture */ case SYS_send: ret = syscall_send(&arg, proc); if (ret) return ret; break; case SYS_recv: syscall_recv(&arg, proc); break; #endif case SYS_sendto: ret = syscall_sendto(&arg, proc); if (ret) return ret; break; case SYS_recvfrom: syscall_recvfrom(&arg, proc); break; case SYS_sendmsg: if ((ret = syscall_sendmsg( &arg, proc))) return ret; break; case SYS_recvmsg: syscall_recvmsg(&arg, proc); break; case SYS_shutdown: syscall_shutdown(&arg, proc); break; case SYS_getpeername: syscall_getpeername(&arg, proc); break; case SYS_getsockopt: syscall_getsockopt(&arg, proc); break; case SYS_setsockopt: syscall_setsockopt(&arg, proc); break; case SYS_clone: syscall_clone(&arg, proc); break; case SYS_execve: syscall_execve(&arg, proc); break; case SYS_exit: XBT_DEBUG("exit(%ld) called", arg.arg[0]); return syscall_exit(&arg, proc); break; case SYS_exit_group: XBT_DEBUG("exit_group(%ld) called", arg.arg[0]); return syscall_exit(&arg, proc); break; case SYS_getpid: syscall_getpid(&arg, proc); break; case SYS_tuxcall: syscall_tuxcall(&arg, proc); break; default: syscall_default(pid, &arg, proc); break; } // Step the traced process ptrace_resume_process(pid); // XBT_DEBUG("process resumed, waitpid"); waitpid(pid, &(proc->status), __WALL); } // while(1) THROW_IMPOSSIBLE; //There's no way to quit the loop return 0; }