void zmq::select_t::loop () { while (!stopping) { // Execute any due timers. int timeout = (int) execute_timers (); // Intialise the pollsets. memcpy (&readfds, &source_set_in, sizeof source_set_in); memcpy (&writefds, &source_set_out, sizeof source_set_out); memcpy (&exceptfds, &source_set_err, sizeof source_set_err); // Wait for events. struct timeval tv = {(long) (timeout / 1000), (long) (timeout % 1000 * 1000)}; #ifdef ZMQ_HAVE_WINDOWS int rc = select (0, &readfds, &writefds, &exceptfds, timeout ? &tv : NULL); wsa_assert (rc != SOCKET_ERROR); #else int rc = select (maxfd + 1, &readfds, &writefds, &exceptfds, timeout ? &tv : NULL); if (rc == -1) { errno_assert (errno == EINTR); continue; } #endif // If there are no events (i.e. it's a timeout) there's no point // in checking the pollset. if (rc == 0) continue; for (fd_set_t::size_type i = 0; i < fds.size (); i ++) { if (fds [i].fd == retired_fd) continue; if (FD_ISSET (fds [i].fd, &exceptfds)) fds [i].events->in_event (); if (fds [i].fd == retired_fd) continue; if (FD_ISSET (fds [i].fd, &writefds)) fds [i].events->out_event (); if (fds [i].fd == retired_fd) continue; if (FD_ISSET (fds [i].fd, &readfds)) fds [i].events->in_event (); } // Destroy retired event sources. if (retired) { fds.erase (std::remove_if (fds.begin (), fds.end (), zmq::select_t::is_retired_fd), fds.end ()); retired = false; } } }
void zmq::poll_t::loop () { while (true) { // Execute any due timers. int timeout = (int) execute_timers (); cleanup_retired (); if (pollset.empty ()) { zmq_assert (get_load () == 0); if (timeout == 0) break; // TODO sleep for timeout continue; } // Wait for events. int rc = poll (&pollset[0], static_cast<nfds_t> (pollset.size ()), timeout ? timeout : -1); #ifdef ZMQ_HAVE_WINDOWS wsa_assert (rc != SOCKET_ERROR); #else if (rc == -1) { errno_assert (errno == EINTR); continue; } #endif // If there are no events (i.e. it's a timeout) there's no point // in checking the pollset. if (rc == 0) continue; for (pollset_t::size_type i = 0; i != pollset.size (); i++) { zmq_assert (!(pollset[i].revents & POLLNVAL)); if (pollset[i].fd == retired_fd) continue; if (pollset[i].revents & (POLLERR | POLLHUP)) fd_table[pollset[i].fd].events->in_event (); if (pollset[i].fd == retired_fd) continue; if (pollset[i].revents & POLLOUT) fd_table[pollset[i].fd].events->out_event (); if (pollset[i].fd == retired_fd) continue; if (pollset[i].revents & POLLIN) fd_table[pollset[i].fd].events->in_event (); } } }
void zmq::poll_t::loop () { while (!stopping) { // Execute any due timers. int timeout = (int) execute_timers (); // Wait for events. int rc = poll (&pollset [0], pollset.size (), timeout ? timeout : -1); if (rc == -1 && errno == EINTR) continue; errno_assert (rc != -1); // If there are no events (i.e. it's a timeout) there's no point // in checking the pollset. if (rc == 0) continue; for (pollset_t::size_type i = 0; i != pollset.size (); i++) { zmq_assert (!(pollset [i].revents & POLLNVAL)); if (pollset [i].fd == retired_fd) continue; if (pollset [i].revents & (POLLERR | POLLHUP)) fd_table [pollset [i].fd].events->in_event (); if (pollset [i].fd == retired_fd) continue; if (pollset [i].revents & POLLOUT) fd_table [pollset [i].fd].events->out_event (); if (pollset [i].fd == retired_fd) continue; if (pollset [i].revents & POLLIN) fd_table [pollset [i].fd].events->in_event (); } // Clean up the pollset and update the fd_table accordingly. if (retired) { pollset_t::size_type i = 0; while (i < pollset.size ()) { if (pollset [i].fd == retired_fd) pollset.erase (pollset.begin () + i); else { fd_table [pollset [i].fd].index = i; i ++; } } retired = false; } } }
void zmq::kqueue_t::loop () { while (!stopping) { // Execute any due timers. int timeout = (int) execute_timers (); // Wait for events. struct kevent ev_buf [max_io_events]; timespec ts = {timeout / 1000, (timeout % 1000) * 1000000}; int n = kevent (kqueue_fd, NULL, 0, &ev_buf [0], max_io_events, timeout ? &ts: NULL); #ifdef HAVE_FORK if (unlikely(pid != getpid())) { //printf("zmq::kqueue_t::loop aborting on forked child %d\n", (int)getpid()); // simply exit the loop in a forked process. return; } #endif if (n == -1) { errno_assert (errno == EINTR); continue; } for (int i = 0; i < n; i ++) { poll_entry_t *pe = (poll_entry_t*) ev_buf [i].udata; if (pe->fd == retired_fd) continue; if (ev_buf [i].flags & EV_EOF) pe->reactor->in_event (); if (pe->fd == retired_fd) continue; if (ev_buf [i].filter == EVFILT_WRITE) pe->reactor->out_event (); if (pe->fd == retired_fd) continue; if (ev_buf [i].filter == EVFILT_READ) pe->reactor->in_event (); } // Destroy retired event sources. for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it) delete *it; retired.clear (); } }
void zmq::devpoll_t::loop () { while (!stopping) { struct pollfd ev_buf [max_io_events]; struct dvpoll poll_req; for (pending_list_t::size_type i = 0; i < pending_list.size (); i ++) fd_table [pending_list [i]].accepted = true; pending_list.clear (); // Execute any due timers. int timeout = (int) execute_timers (); // Wait for events. // On Solaris, we can retrieve no more then (OPEN_MAX - 1) events. poll_req.dp_fds = &ev_buf [0]; #if defined ZMQ_HAVE_SOLARIS poll_req.dp_nfds = std::min ((int) max_io_events, OPEN_MAX - 1); #else poll_req.dp_nfds = max_io_events; #endif poll_req.dp_timeout = timeout ? timeout : -1; int n = ioctl (devpoll_fd, DP_POLL, &poll_req); if (n == -1 && errno == EINTR) continue; errno_assert (n != -1); for (int i = 0; i < n; i ++) { fd_entry_t *fd_ptr = &fd_table [ev_buf [i].fd]; if (!fd_ptr->valid || !fd_ptr->accepted) continue; if (ev_buf [i].revents & (POLLERR | POLLHUP)) fd_ptr->reactor->in_event (); if (!fd_ptr->valid || !fd_ptr->accepted) continue; if (ev_buf [i].revents & POLLOUT) fd_ptr->reactor->out_event (); if (!fd_ptr->valid || !fd_ptr->accepted) continue; if (ev_buf [i].revents & POLLIN) fd_ptr->reactor->in_event (); } } }
void zmq::pollset_t::loop () { struct pollfd polldata_array[max_io_events]; while (!stopping) { // Execute any due timers. int timeout = (int) execute_timers (); // Wait for events. int n = pollset_poll(pollset_fd, polldata_array, max_io_events, timeout ? timeout : -1); if (n == -1) { errno_assert (errno == EINTR); continue; } for (int i = 0; i < n; i ++) { poll_entry_t *pe = fd_table [polldata_array [i].fd]; if (!pe) continue; if (pe->fd == retired_fd) continue; if (polldata_array [i].revents & (POLLERR | POLLHUP)) pe->events->in_event (); if (pe->fd == retired_fd) continue; if (polldata_array [i].revents & POLLOUT) pe->events->out_event (); if (pe->fd == retired_fd) continue; if (polldata_array [i].revents & POLLIN) pe->events->in_event (); } // Destroy retired event sources. for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it) LIBZMQ_DELETE(*it); retired.clear (); } }
void zmq::epoll_t::loop () { epoll_event ev_buf [max_io_events]; while (!stopping) { // Execute any due timers. int timeout = (int) execute_timers (); // Wait for events. int n = epoll_wait (epoll_fd, &ev_buf [0], max_io_events, timeout ? timeout : -1); if (n == -1) { errno_assert (errno == EINTR); continue; } for (int i = 0; i < n; i ++) { poll_entry_t *pe = ((poll_entry_t*) ev_buf [i].data.ptr); if (pe->fd == retired_fd) continue; if (ev_buf [i].events & (EPOLLERR | EPOLLHUP)) pe->events->in_event (); if (pe->fd == retired_fd) continue; if (ev_buf [i].events & EPOLLOUT) pe->events->out_event (); if (pe->fd == retired_fd) continue; if (ev_buf [i].events & EPOLLIN) pe->events->in_event (); } // Destroy retired event sources. retired_sync.lock (); for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it) { LIBZMQ_DELETE(*it); } retired.clear (); retired_sync.unlock (); } }
void zmq::kqueue_t::loop () { while (!stopping) { // Execute any due timers. int timeout = (int) execute_timers (); // Wait for events. struct kevent ev_buf [max_io_events]; timespec ts = {timeout / 1000, (timeout % 1000) * 1000000}; int n = kevent (kqueue_fd, NULL, 0, &ev_buf [0], max_io_events, timeout ? &ts: NULL); if (n == -1) { errno_assert (errno == EINTR); continue; } for (int i = 0; i < n; i ++) { poll_entry_t *pe = (poll_entry_t*) ev_buf [i].udata; if (pe->fd == retired_fd) continue; if (ev_buf [i].flags & EV_EOF) pe->reactor->in_event (); if (pe->fd == retired_fd) continue; if (ev_buf [i].filter == EVFILT_WRITE) pe->reactor->out_event (); if (pe->fd == retired_fd) continue; if (ev_buf [i].filter == EVFILT_READ) pe->reactor->in_event (); } // Destroy retired event sources. for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it) delete *it; retired.clear (); } }
void device_scheduler::timeslice() { bool call_debugger = ((machine().debug_flags & DEBUG_FLAG_ENABLED) != 0); // build the execution list if we don't have one yet if (m_execute_list == NULL) rebuild_execute_list(); // execute timers execute_timers(); // loop until we hit the next timer while (m_basetime < m_timer_list->m_expire) { // by default, assume our target is the end of the next quantum attotime target = m_basetime + attotime(0, m_quantum_list.first()->m_actual); // however, if the next timer is going to fire before then, override if (m_timer_list->m_expire < target) target = m_timer_list->m_expire; LOG(("------------------\n")); LOG(("cpu_timeslice: target = %s\n", target.as_string())); // do we have pending suspension changes? if (m_suspend_changes_pending) apply_suspend_changes(); // loop over non-suspended CPUs for (device_execute_interface *exec = m_execute_list; exec != NULL; exec = exec->m_nextexec) { // only process if our target is later than the CPU's current time (coarse check) if (target.seconds >= exec->m_localtime.seconds) { // compute how many attoseconds to execute this CPU attoseconds_t delta = target.attoseconds - exec->m_localtime.attoseconds; if (delta < 0 && target.seconds > exec->m_localtime.seconds) delta += ATTOSECONDS_PER_SECOND; assert(delta == (target - exec->m_localtime).as_attoseconds()); // if we have enough for at least 1 cycle, do the math if (delta >= exec->m_attoseconds_per_cycle) { // compute how many cycles we want to execute int ran = exec->m_cycles_running = divu_64x32((UINT64)delta >> exec->m_divshift, exec->m_divisor); LOG((" cpu '%s': %d cycles\n", exec->device().tag(), exec->m_cycles_running)); // if we're not suspended, actually execute if (exec->m_suspend == 0) { g_profiler.start(exec->m_profiler); // note that this global variable cycles_stolen can be modified // via the call to cpu_execute exec->m_cycles_stolen = 0; m_executing_device = exec; *exec->m_icountptr = exec->m_cycles_running; if (!call_debugger) exec->run(); else { debugger_start_cpu_hook(&exec->device(), target); exec->run(); debugger_stop_cpu_hook(&exec->device()); } // adjust for any cycles we took back assert(ran >= *exec->m_icountptr); ran -= *exec->m_icountptr; assert(ran >= exec->m_cycles_stolen); ran -= exec->m_cycles_stolen; g_profiler.stop(); } // account for these cycles exec->m_totalcycles += ran; // update the local time for this CPU attotime delta = attotime(0, exec->m_attoseconds_per_cycle * ran); assert(delta >= attotime::zero); exec->m_localtime += delta; LOG((" %d ran, %d total, time = %s\n", ran, (INT32)exec->m_totalcycles, exec->m_localtime.as_string())); // if the new local CPU time is less than our target, move the target up, but not before the base if (exec->m_localtime < target) { assert(exec->m_localtime < target); target = max(exec->m_localtime, m_basetime); LOG((" (new target)\n")); } } } }
void zmq::select_t::loop () { while (!stopping) { // Execute any due timers. int timeout = (int) execute_timers (); #if defined ZMQ_HAVE_OSX struct timeval tv = { (long) (timeout / 1000), timeout % 1000 * 1000 }; #else struct timeval tv = { (long) (timeout / 1000), (long) (timeout % 1000 * 1000) }; #endif int rc = 0; #if defined ZMQ_HAVE_WINDOWS /* On Windows select does not allow to mix descriptors from different service providers. It seems to work for AF_INET and AF_INET6, but fails for AF_INET and VMCI. The workaround is to use WSAEventSelect and WSAWaitForMultipleEvents to wait, then use select to find out what actually changed. WSAWaitForMultipleEvents cannot be used alone, because it does not support more than 64 events which is not enough. To reduce unncessary overhead, WSA is only used when there are more than one family. Moreover, AF_INET and AF_INET6 are considered the same family because Windows seems to handle them properly. See get_fd_family for details. */ wsa_events_t wsa_events; // If there is just one family, there is no reason to use WSA events. if (family_entries.size () > 1) { for (family_entries_t::iterator family_entry_it = family_entries.begin (); family_entry_it != family_entries.end (); ++family_entry_it) { family_entry_t& family_entry = family_entry_it->second; for (fd_entries_t::iterator fd_entry_it = family_entry.fd_entries.begin (); fd_entry_it != family_entry.fd_entries.end (); ++fd_entry_it) { fd_t fd = fd_entry_it->fd; // http://stackoverflow.com/q/35043420/188530 if (FD_ISSET (fd, &family_entry.fds_set.read) && FD_ISSET (fd, &family_entry.fds_set.write)) rc = WSAEventSelect (fd, wsa_events.events [3], FD_READ | FD_ACCEPT | FD_CLOSE | FD_WRITE | FD_CONNECT | FD_OOB); else if (FD_ISSET (fd, &family_entry.fds_set.read)) rc = WSAEventSelect (fd, wsa_events.events [0], FD_READ | FD_ACCEPT | FD_CLOSE | FD_OOB); else if (FD_ISSET (fd, &family_entry.fds_set.write)) rc = WSAEventSelect (fd, wsa_events.events [1], FD_WRITE | FD_CONNECT | FD_OOB); else if (FD_ISSET (fd, &family_entry.fds_set.error)) rc = WSAEventSelect (fd, wsa_events.events [2], FD_OOB); else rc = 0; wsa_assert (rc != SOCKET_ERROR); } } } #endif #if defined ZMQ_HAVE_WINDOWS if (family_entries.size () > 1) { rc = WSAWaitForMultipleEvents (4, wsa_events.events, FALSE, timeout ? timeout : INFINITE, FALSE); wsa_assert (rc != (int)WSA_WAIT_FAILED); zmq_assert (rc != WSA_WAIT_IO_COMPLETION); if (rc == WSA_WAIT_TIMEOUT) continue; } for (current_family_entry_it = family_entries.begin (); current_family_entry_it != family_entries.end (); ++current_family_entry_it) { family_entry_t& family_entry = current_family_entry_it->second; // select will fail when run with empty sets. if (family_entry.fd_entries.empty ()) continue; fds_set_t local_fds_set = family_entry.fds_set; if (family_entries.size () > 1) { // There is no reason to wait again after WSAWaitForMultipleEvents. // Simply collect what is ready. struct timeval tv_nodelay = { 0, 0 }; rc = select (0, &local_fds_set.read, &local_fds_set.write, &local_fds_set.error, &tv_nodelay); } else rc = select (0, &local_fds_set.read, &local_fds_set.write, &local_fds_set.error, timeout > 0 ? &tv : NULL); wsa_assert (rc != SOCKET_ERROR); // Size is cached to avoid iteration through recently added descriptors. for (fd_entries_t::size_type i = 0, size = family_entry.fd_entries.size (); i < size && rc > 0; ++i) { fd_entry_t fd_entry = family_entry.fd_entries [i]; if (fd_entry.fd == retired_fd) continue; if (FD_ISSET (fd_entry.fd, &local_fds_set.read)) { fd_entry.events->in_event (); --rc; } if (fd_entry.fd == retired_fd || rc == 0) continue; if (FD_ISSET (fd_entry.fd, &local_fds_set.write)) { fd_entry.events->out_event (); --rc; } if (fd_entry.fd == retired_fd || rc == 0) continue; if (FD_ISSET (fd_entry.fd, &local_fds_set.error)) { fd_entry.events->in_event (); --rc; } } if (family_entry.retired) { family_entry.retired = false; family_entry.fd_entries.erase (std::remove_if (family_entry.fd_entries.begin (), family_entry.fd_entries.end (), is_retired_fd), family_entry.fd_entries.end ()); } } #else fds_set_t local_fds_set = fds_set; rc = select (maxfd + 1, &local_fds_set.read, &local_fds_set.write, &local_fds_set.error, timeout ? &tv : NULL); if (rc == -1) { errno_assert (errno == EINTR); continue; } // Size is cached to avoid iteration through just added descriptors. for (fd_entries_t::size_type i = 0, size = fd_entries.size (); i < size && rc > 0; ++i) { fd_entry_t& fd_entry = fd_entries [i]; if (fd_entry.fd == retired_fd) continue; if (FD_ISSET (fd_entry.fd, &local_fds_set.read)) { fd_entry.events->in_event (); --rc; } if (fd_entry.fd == retired_fd || rc == 0) continue; if (FD_ISSET (fd_entry.fd, &local_fds_set.write)) { fd_entry.events->out_event (); --rc; } if (fd_entry.fd == retired_fd || rc == 0) continue; if (FD_ISSET (fd_entry.fd, &local_fds_set.error)) { fd_entry.events->in_event (); --rc; } } if (retired) { retired = false; fd_entries.erase (std::remove_if (fd_entries.begin (), fd_entries.end (), is_retired_fd), fd_entries.end ()); } #endif } }