job make_job_with_id(unsigned int pri, unsigned int delay, unsigned int ttr, int body_size, tube tube, unsigned long long id) { job j; j = allocate_job(body_size); if (!j) return twarnx("OOM"), (job) 0; if (id) { j->id = id; if (id >= next_id) next_id = id + 1; } else { j->id = next_id++; } j->pri = pri; j->delay = delay; j->ttr = ttr; store_job(j); TUBE_ASSIGN(j->tube, tube); return j; }
//============================================================================= int Multiplexer::spin() { fd_set fds_read; FD_ZERO(&fds_read); fd_set fds_write; FD_ZERO(&fds_write); fd_set fds_except; FD_ZERO(&fds_except); Date expiry = Date::now() + Time(m_latency); check_thread_pool(); m_job_mutex.lock(); // Add any new jobs into the jobs list m_new_mutex.lock(); while (!m_jobs_new.empty()) { m_jobs.push_back(m_jobs_new.front()); m_jobs_new.pop_front(); expiry = Date::now(); } m_new_mutex.unlock(); // Return and exit if there are no jobs int num = m_jobs.size(); if (num == 0) { m_job_mutex.unlock(); return -1; } // Find jobs to run int num_added=0; int maxfd=m_wakeup[0]; FD_SET(m_wakeup[0],&fds_read); // Add wakeup socket JobList::iterator it; for (it = m_jobs.begin(); it != m_jobs.end(); ++it) { Job* job = *it; int mask = 0; if (job->prepare(expiry, mask)) { int fd = job->get_fd(); if (fd >= 0) { ++num_added; if (0 != (mask & (1<<Stream::Readable))) FD_SET(fd,&fds_read); if (0 != (mask & (1<<Stream::Writeable))) FD_SET(fd,&fds_write); FD_SET(fd,&fds_except); maxfd = std::max(maxfd,fd); } } } m_job_mutex.unlock(); if (num_added == 0) { return 0; } timeval timeout; (expiry - Date::now()).get_timeval(timeout); if (timeout.tv_sec < 0 || timeout.tv_usec < 0) { timeout.tv_sec = 0; timeout.tv_usec = 0; } // Make the select call if (select(maxfd+1, &fds_read, &fds_write, &fds_except, &timeout) < 0) { // Select returned an error or it was interrupted if (errno != EINTR) { DEBUG_LOG_ERRNO("select failed"); } } else { Date start = Date::now(); // Select succeeded, decode events and allocate jobs for (it = m_jobs.begin(); it != m_jobs.end(); ++it) { Job* job = *it; int events = 0; int fd = job->get_fd(); if (fd >= 0) { events |= (FD_ISSET(fd,&fds_read) ? (1<<Stream::Readable) : 0); events |= (FD_ISSET(fd,&fds_write) ? (1<<Stream::Writeable) : 0); } if (job->ready(events)) { allocate_job(job); ++m_jobs_run; } } update_stats(Date::now() - start); // Read from the wakeup socket to clear if (FD_ISSET(m_wakeup[0],&fds_read)) { char buffer[16]; recv(m_wakeup[0],buffer,16,0); } } // Purge jobs m_job_mutex.lock(); for (it = m_jobs.begin(); it != m_jobs.end(); ) { Job* job = *it; if (job->get_state() == Job::Purge) { it = m_jobs.erase(it); delete job; } else { it++; } } m_end_condition.signal(); m_job_mutex.unlock(); return 0; }