📄 scheduler.c++
字号:
// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.// // This program is free software; you can redistribute it and/or modify it// under the terms of version 2 of the GNU General Public License as// published by the Free Software Foundation.//// This program is distributed in the hope that it would be useful, but// WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any// license provided herein, whether implied or otherwise, is limited to// this program in accordance with the express provisions of the GNU// General Public License. Patent licenses, if any, provided herein do not// apply to combinations of this program with other product or programs, or// any other product whatsoever. This program is distributed without any// warranty that the program is delivered free of the rightful claim of any// third person by way of infringement or the like. See the GNU General// Public License for more details.//// You should have received a copy of the GNU General Public License along// with this program; if not, write the Free Software Foundation, Inc., 59// Temple Place - Suite 330, Boston MA 02111-1307, USA.#include "Scheduler.h"#include <assert.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <sys/param.h>#include "Log.h"#include "timeval.h"// Define a bunch of class-global variables.Scheduler::IOTypeInfo Scheduler::read(&FDInfo::read);Scheduler::IOTypeInfo Scheduler::write(&FDInfo::write);unsigned int Scheduler::nfds;Scheduler::FDInfo *Scheduler::fdinfo;unsigned int Scheduler::nfdinfo_alloc;unsigned int Scheduler::ntasks;Scheduler::TimedProc Scheduler::recurring_proc;void *Scheduler::recurring_closure;timeval Scheduler::next_task_time;timeval Scheduler::recurring_interval;Scheduler::onetime_task *Scheduler::first_task;bool Scheduler::running;//////////////////////////////////////////////////////////////////////////////// One time task codevoidScheduler::install_onetime_task(const timeval& when, TimedProc proc, void *closure){ onetime_task **fp = &first_task; while (*fp && (*fp)->when < when) fp = &(*fp)->next; onetime_task *nt = new onetime_task; nt->next = *fp; *fp = nt; nt->when = when; nt->proc = proc; nt->closure = closure; ntasks++;}voidScheduler::remove_onetime_task(TimedProc proc, void *closure){ onetime_task *p, **pp = &first_task; while ((p = *pp) != NULL) { if (p->proc == proc && p->closure == closure) { *pp = p->next; delete p; ntasks--; break; } pp = &p->next; }}//////////////////////////////////////////////////////////////////////////////// Recurring task codevoidScheduler::install_recurring_task(const timeval& interval, TimedProc proc, void *closure){ timeval now; assert(!recurring_proc); assert(proc); assert(interval.tv_sec >= 0); assert(interval.tv_usec >= 0 && interval.tv_usec < 1000000); assert(interval.tv_sec || interval.tv_usec); recurring_proc = proc; recurring_closure = closure; recurring_interval = interval; ntasks++; (void) gettimeofday(&now, NULL); next_task_time = now + interval;}voidScheduler::remove_recurring_task(TimedProc proc, void *closure){ assert(proc == recurring_proc); assert(closure == recurring_closure); recurring_proc = NULL; recurring_closure = closure; timerclear(&recurring_interval); ntasks--;}// do_tasks activates all timer based tasks. It also sets// next_task_time to the absolute time when it should next be// invoked.voidScheduler::do_tasks(){ if (ntasks) { timeval now; (void) gettimeofday(&now, NULL); if (recurring_proc && now >= next_task_time) { // Time for the next task. (*recurring_proc)(recurring_closure); next_task_time += recurring_interval; // If the clock has jumped ahead or we've gotten too far behind, // postpone the next task. if (next_task_time < now) next_task_time = now + recurring_interval; } else { timeval time_left = next_task_time - now; if (recurring_interval < time_left) { // More time left than we started with -- clock must have // run backward. Reset next_task_time to sane value. next_task_time = now + recurring_interval; } } while (first_task && first_task->when < now) { TimedProc proc = first_task->proc; void *closure = first_task->closure; remove_onetime_task(proc, closure); (*proc)(closure); } }}// calc_timeout calculates the timeout to pass to select().// It returns:// NULL (if no timed tasks exist)// zero time (if it's time for the next task)// nonzero time (if it's not time yet)timeval *Scheduler::calc_timeout(){ static timeval sleep_interval; if (ntasks) { timeval wake_time; if (recurring_proc) wake_time = next_task_time; if (!recurring_proc || first_task && first_task->when < wake_time) wake_time = first_task->when; timeval now; (void) gettimeofday(&now, NULL); sleep_interval = wake_time - now; if (sleep_interval.tv_sec < 0) timerclear(&sleep_interval); return &sleep_interval; } else return NULL;}//////////////////////////////////////////////////////////////////////////////// I/O handler code// fd_to_info converts a file descriptor to a pointer into the// fdinfo array. On the way, it verifies that the array has// been allocated far enough out.Scheduler::FDInfo *Scheduler::fd_to_info(int fd){ assert(fd >= 0); if (nfds < fd + 1) { if (nfdinfo_alloc < fd + 1) { unsigned newalloc = nfdinfo_alloc * 3 / 2 + 10; if (newalloc < fd + 1) newalloc = fd + 1; FDInfo *newinfo = new FDInfo[newalloc]; for (unsigned i = 0; i < nfds; i++) newinfo[i] = fdinfo[i]; delete [] fdinfo; fdinfo = newinfo; nfdinfo_alloc = newalloc; } // Zero all new fdinfo's. memset(&fdinfo[nfds], 0, (fd + 1 - nfds) * sizeof *fdinfo); nfds = fd + 1; } return &fdinfo[fd];}// trim_fdinfo makes the fdinfo array smaller if its last entries// aren't being used. The memory isn't actually freed unless the// array is completely zeroed out.voidScheduler::trim_fdinfo(){ for (FDInfo *fp = &fdinfo[nfds - 1]; nfds > 0; --nfds, --fp) if (fp->read.handler || fp->write.handler) break; if (!nfds) { delete [] fdinfo; fdinfo = NULL; nfdinfo_alloc = 0; }}Scheduler::IOHandlerScheduler::install_io_handler(int fd, IOHandler handler, void *closure, IOTypeInfo *iotype){ assert(fd >= 0); assert(handler); FDInfo *fp = fd_to_info(fd); IOHandler old_handler = (fp->*(iotype->iotype)).handler; (fp->*(iotype->iotype)).handler = handler; (fp->*(iotype->iotype)).closure = closure; assert(!old_handler || FD_ISSET(fd, &iotype->fds)); if (!FD_ISSET(fd, &iotype->fds)) { FD_SET(fd, &iotype->fds); iotype->nbitsset++; } return old_handler;}Scheduler::IOHandlerScheduler::remove_io_handler(int fd, IOTypeInfo *iotype){ assert(fd >= 0 && fd < nfds); FDInfo *fp = fd_to_info(fd); IOHandler old_handler = (fp->*(iotype->iotype)).handler; (fp->*(iotype->iotype)).handler = NULL; (fp->*(iotype->iotype)).closure = NULL; trim_fdinfo(); assert(old_handler); if (FD_ISSET(fd, &iotype->fds)) { FD_CLR(fd, &iotype->fds); iotype->nbitsset--; } return old_handler;}Scheduler::IOHandlerScheduler::install_read_handler(int fd, IOHandler handler, void *closure){ return install_io_handler(fd, handler, closure, &read);}Scheduler::IOHandlerScheduler::remove_read_handler(int fd){ return remove_io_handler(fd, &read);}Scheduler::IOHandlerScheduler::install_write_handler(int fd, IOHandler handler, void *closure){ return install_io_handler(fd, handler, closure, &write);}Scheduler::IOHandlerScheduler::remove_write_handler(int fd){ return remove_io_handler(fd, &write);}voidScheduler::handle_io(const fd_set *fds, FDInfo::FDIOHandler FDInfo::* iotype){ if (fds) for (int fd = 0; fd < nfds; fd++) if (FD_ISSET(fd, fds)) { FDInfo *fp = &fdinfo[fd]; assert(iotype == &FDInfo::read || iotype == &FDInfo::write); (fp->*iotype).handler(fd, (fp->*iotype).closure); // Remember, handler may move fdinfo array. }}// Scheduling priorities defined here: writable descriptors have// highest priority, followed by exceptionable descriptors, then// readable descriptors, then timed tasks have the lowest priority.voidScheduler::select(){ fd_set readfds, writefds; readfds = Scheduler::read.fds; writefds = Scheduler::write.fds; timeval *timeout = calc_timeout(); int status = ::select(nfds, &readfds, &writefds, 0, timeout); if (status == -1 && errno != EINTR) { Log::perror("select"); // Oh, no! ::exit(1); } if (status > 0) { // I/O is ready -- find it and do it. handle_io( &writefds, &FDInfo::write ); handle_io( &readfds, &FDInfo::read ); } // Check for tasks now. do_tasks();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -