[BACK]Return to Scheduler.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

Annotation of fam/fam/Scheduler.c++, Revision 1.1.1.1

1.1       trev        1: //  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
                      2: //
                      3: //  This program is free software; you can redistribute it and/or modify it
                      4: //  under the terms of version 2 of the GNU General Public License as
                      5: //  published by the Free Software Foundation.
                      6: //
                      7: //  This program is distributed in the hope that it would be useful, but
                      8: //  WITHOUT ANY WARRANTY; without even the implied warranty of
                      9: //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
                     10: //  license provided herein, whether implied or otherwise, is limited to
                     11: //  this program in accordance with the express provisions of the GNU
                     12: //  General Public License.  Patent licenses, if any, provided herein do not
                     13: //  apply to combinations of this program with other product or programs, or
                     14: //  any other product whatsoever.  This program is distributed without any
                     15: //  warranty that the program is delivered free of the rightful claim of any
                     16: //  third person by way of infringement or the like.  See the GNU General
                     17: //  Public License for more details.
                     18: //
                     19: //  You should have received a copy of the GNU General Public License along
                     20: //  with this program; if not, write the Free Software Foundation, Inc., 59
                     21: //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
                     22:
                     23: #include "Scheduler.h"
                     24:
                     25: #include <assert.h>
                     26: #include <string.h>
                     27: #include <errno.h>
                     28: #include <unistd.h>
                     29: #include <stdlib.h>
                     30: #include <sys/param.h>
                     31:
                     32: #include "Log.h"
                     33: #include "timeval.h"
                     34:
                     35: //  Define a bunch of class-global variables.
                     36:
                     37: Scheduler::IOTypeInfo	 Scheduler::read(&FDInfo::read);
                     38: Scheduler::IOTypeInfo	 Scheduler::write(&FDInfo::write);
                     39: unsigned int		 Scheduler::nfds;
                     40: Scheduler::FDInfo	*Scheduler::fdinfo;
                     41: unsigned int		 Scheduler::nfdinfo_alloc;
                     42:
                     43: unsigned int		 Scheduler::ntasks;
                     44: Scheduler::TimedProc	 Scheduler::recurring_proc;
                     45: void			*Scheduler::recurring_closure;
                     46: timeval			 Scheduler::next_task_time;
                     47: timeval			 Scheduler::recurring_interval;
                     48: Scheduler::onetime_task	*Scheduler::first_task;
                     49: bool			 Scheduler::running;
                     50:
                     51:
                     52: //////////////////////////////////////////////////////////////////////////////
                     53: //  One time task code
                     54:
                     55: void
                     56: Scheduler::install_onetime_task(const timeval& when,
                     57: 				TimedProc proc, void *closure)
                     58: {
                     59:     onetime_task **fp = &first_task;
                     60:     while (*fp && (*fp)->when < when)
                     61: 	fp = &(*fp)->next;
                     62:     onetime_task *nt = new onetime_task;
                     63:     nt->next = *fp;
                     64:     *fp = nt;
                     65:     nt->when = when;
                     66:     nt->proc = proc;
                     67:     nt->closure = closure;
                     68:     ntasks++;
                     69: }
                     70:
                     71: void
                     72: Scheduler::remove_onetime_task(TimedProc proc, void *closure)
                     73: {
                     74:     onetime_task *p, **pp = &first_task;
                     75:     while ((p = *pp) != NULL)
                     76:     {
                     77:         if (p->proc == proc && p->closure == closure)
                     78: 	{   *pp = p->next;
                     79: 	    delete p;
                     80: 	    ntasks--;
                     81: 	    break;
                     82: 	}
                     83: 	pp = &p->next;
                     84:     }
                     85: }
                     86:
                     87: //////////////////////////////////////////////////////////////////////////////
                     88: //  Recurring task code
                     89:
                     90: void
                     91: Scheduler::install_recurring_task(const timeval& interval,
                     92: 				  TimedProc proc, void *closure)
                     93: {
                     94:     timeval now;
                     95:
                     96:     assert(!recurring_proc);
                     97:     assert(proc);
                     98:     assert(interval.tv_sec >= 0);
                     99:     assert(interval.tv_usec >= 0 && interval.tv_usec < 1000000);
                    100:     assert(interval.tv_sec || interval.tv_usec);
                    101:
                    102:     recurring_proc = proc;
                    103:     recurring_closure = closure;
                    104:     recurring_interval = interval;
                    105:     ntasks++;
                    106:     (void) gettimeofday(&now, NULL);
                    107:     next_task_time = now + interval;
                    108: }
                    109:
                    110: void
                    111: Scheduler::remove_recurring_task(TimedProc proc, void *closure)
                    112: {
                    113:     assert(proc == recurring_proc);
                    114:     assert(closure == recurring_closure);
                    115:
                    116:     recurring_proc = NULL;
                    117:     recurring_closure = closure;
                    118:     timerclear(&recurring_interval);
                    119:     ntasks--;
                    120: }
                    121:
                    122: //  do_tasks activates all timer based tasks.  It also sets
                    123: //  next_task_time to the absolute time when it should next be
                    124: //  invoked.
                    125:
                    126: void
                    127: Scheduler::do_tasks()
                    128: {
                    129:     if (ntasks)
                    130:     {
                    131:         timeval now;
                    132: 	(void) gettimeofday(&now, NULL);
                    133: 	if (recurring_proc && now >= next_task_time)
                    134: 	{
                    135: 	    // Time for the next task.
                    136:
                    137:             (*recurring_proc)(recurring_closure);
                    138: 	    next_task_time += recurring_interval;
                    139:
                    140: 	    // If the clock has jumped ahead or we've gotten too far behind,
                    141: 	    // postpone the next task.
                    142:
                    143: 	    if (next_task_time < now)
                    144: 		next_task_time = now + recurring_interval;
                    145: 	}
                    146: 	else
                    147: 	{   timeval time_left = next_task_time - now;
                    148: 	    if (recurring_interval < time_left)
                    149: 	    {
                    150: 		// More time left than we started with -- clock must have
                    151: 		// run backward.  Reset next_task_time to sane value.
                    152:
                    153: 		next_task_time = now + recurring_interval;
                    154: 	    }
                    155: 	}
                    156:
                    157: 	while (first_task && first_task->when < now)
                    158: 	{   TimedProc proc = first_task->proc;
                    159: 	    void *closure = first_task->closure;
                    160: 	    remove_onetime_task(proc, closure);
                    161: 	    (*proc)(closure);
                    162: 	}
                    163:     }
                    164: }
                    165:
                    166: //  calc_timeout calculates the timeout to pass to select().
                    167: //  It returns:
                    168: //		NULL (if no timed tasks exist)
                    169: //		zero time (if it's time for the next task)
                    170: //		nonzero time (if it's not time yet)
                    171:
                    172: timeval *
                    173: Scheduler::calc_timeout()
                    174: {
                    175:     static timeval sleep_interval;
                    176:
                    177:     if (ntasks)
                    178:     {
                    179: 	timeval wake_time;
                    180: 	if (recurring_proc)
                    181: 	    wake_time = next_task_time;
                    182: 	if (!recurring_proc || first_task && first_task->when < wake_time)
                    183: 	    wake_time = first_task->when;
                    184: 	timeval now;
                    185: 	(void) gettimeofday(&now, NULL);
                    186: 	sleep_interval = wake_time - now;
                    187: 	if (sleep_interval.tv_sec < 0)
                    188: 	    timerclear(&sleep_interval);
                    189: 	return &sleep_interval;
                    190:     }
                    191:     else
                    192: 	return NULL;
                    193: }
                    194:
                    195: //////////////////////////////////////////////////////////////////////////////
                    196: //  I/O handler code
                    197:
                    198: //  fd_to_info converts a file descriptor to a pointer into the
                    199: //  fdinfo array.  On the way, it verifies that the array has
                    200: //  been allocated far enough out.
                    201:
                    202: Scheduler::FDInfo *
                    203: Scheduler::fd_to_info(int fd)
                    204: {
                    205:     assert(fd >= 0);
                    206:     if (nfds < fd + 1)
                    207:     {
                    208: 	if (nfdinfo_alloc < fd + 1)
                    209: 	{
                    210: 	    unsigned newalloc = nfdinfo_alloc * 3 / 2 + 10;
                    211: 	    if (newalloc < fd + 1)
                    212: 		newalloc = fd + 1;
                    213: 	    FDInfo *newinfo = new FDInfo[newalloc];
                    214: 	    for (unsigned i = 0; i < nfds; i++)
                    215: 		newinfo[i] = fdinfo[i];
                    216: 	    delete [] fdinfo;
                    217: 	    fdinfo = newinfo;
                    218: 	    nfdinfo_alloc = newalloc;
                    219: 	}
                    220:
                    221: 	// Zero all new fdinfo's.
                    222: 	memset(&fdinfo[nfds], 0, (fd + 1 - nfds) * sizeof *fdinfo);
                    223: 	nfds = fd + 1;
                    224:     }
                    225:     return &fdinfo[fd];
                    226: }
                    227:
                    228: //  trim_fdinfo makes the fdinfo array smaller if its last entries
                    229: //  aren't being used.  The memory isn't actually freed unless the
                    230: //  array is completely zeroed out.
                    231:
                    232: void
                    233: Scheduler::trim_fdinfo()
                    234: {
                    235:     for (FDInfo *fp = &fdinfo[nfds - 1]; nfds > 0; --nfds, --fp)
                    236: 	if (fp->read.handler || fp->write.handler)
                    237: 	    break;
                    238:
                    239:     if (!nfds)
                    240:     {   delete [] fdinfo;
                    241: 	fdinfo = NULL;
                    242: 	nfdinfo_alloc = 0;
                    243:     }
                    244: }
                    245:
                    246: Scheduler::IOHandler
                    247: Scheduler::install_io_handler(int fd, IOHandler handler, void *closure,
                    248: 			      IOTypeInfo *iotype)
                    249: {
                    250:     assert(fd >= 0);
                    251:     assert(handler);
                    252:     FDInfo *fp = fd_to_info(fd);
                    253:     IOHandler old_handler = (fp->*(iotype->iotype)).handler;
                    254:     (fp->*(iotype->iotype)).handler = handler;
                    255:     (fp->*(iotype->iotype)).closure = closure;
                    256:     assert(!old_handler || FD_ISSET(fd, &iotype->fds));
                    257:     if (!FD_ISSET(fd, &iotype->fds))
                    258:     {
                    259:         FD_SET(fd, &iotype->fds);
                    260:         iotype->nbitsset++;
                    261:     }
                    262:     return old_handler;
                    263: }
                    264:
                    265: Scheduler::IOHandler
                    266: Scheduler::remove_io_handler(int fd, IOTypeInfo *iotype)
                    267: {
                    268:     assert(fd >= 0 && fd < nfds);
                    269:     FDInfo *fp = fd_to_info(fd);
                    270:     IOHandler old_handler = (fp->*(iotype->iotype)).handler;
                    271:     (fp->*(iotype->iotype)).handler = NULL;
                    272:     (fp->*(iotype->iotype)).closure = NULL;
                    273:     trim_fdinfo();
                    274:     assert(old_handler);
                    275:     if (FD_ISSET(fd, &iotype->fds))
                    276:     {
                    277:         FD_CLR(fd, &iotype->fds);
                    278:         iotype->nbitsset--;
                    279:     }
                    280:     return old_handler;
                    281: }
                    282:
                    283: Scheduler::IOHandler
                    284: Scheduler::install_read_handler(int fd, IOHandler handler, void *closure)
                    285: {
                    286:     return install_io_handler(fd, handler, closure, &read);
                    287: }
                    288:
                    289: Scheduler::IOHandler
                    290: Scheduler::remove_read_handler(int fd)
                    291: {
                    292:     return remove_io_handler(fd, &read);
                    293: }
                    294:
                    295: Scheduler::IOHandler
                    296: Scheduler::install_write_handler(int fd, IOHandler handler, void *closure)
                    297: {
                    298:     return install_io_handler(fd, handler, closure, &write);
                    299: }
                    300:
                    301: Scheduler::IOHandler
                    302: Scheduler::remove_write_handler(int fd)
                    303: {
                    304:     return remove_io_handler(fd, &write);
                    305: }
                    306:
                    307: void
                    308: Scheduler::handle_io(const fd_set *fds, FDInfo::FDIOHandler FDInfo::* iotype)
                    309: {
                    310:     if (fds)
                    311: 	for (int fd = 0; fd < nfds; fd++)
                    312: 	    if (FD_ISSET(fd, fds))
                    313: 	    {   FDInfo *fp = &fdinfo[fd];
                    314: 		assert(iotype == &FDInfo::read || iotype == &FDInfo::write);
                    315: 		(fp->*iotype).handler(fd, (fp->*iotype).closure);
                    316: 		// Remember, handler may move fdinfo array.
                    317: 	    }
                    318: }
                    319:
                    320: // Scheduling priorities defined here: writable descriptors have
                    321: // highest priority, followed by exceptionable descriptors, then
                    322: // readable descriptors, then timed tasks have the lowest priority.
                    323:
                    324: void
                    325: Scheduler::select()
                    326: {
                    327:     fd_set readfds, writefds;
                    328:     readfds = Scheduler::read.fds;
                    329:     writefds =  Scheduler::write.fds;
                    330:     timeval *timeout   = calc_timeout();
                    331:
                    332:     int status = ::select(nfds, &readfds, &writefds, 0, timeout);
                    333:
                    334:     if (status == -1 && errno != EINTR)
                    335:     {   Log::perror("select");		// Oh, no!
                    336: 	::exit(1);
                    337:     }
                    338:     if (status > 0)
                    339:     {
                    340: 	// I/O is ready -- find it and do it.
                    341:
                    342: 	handle_io( &writefds, &FDInfo::write );
                    343: 	handle_io(  &readfds, &FDInfo::read  );
                    344:     }
                    345:
                    346:     // Check for tasks now.
                    347:
                    348:     do_tasks();
                    349: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>