Files
pvvmud/common/lib/srvcli/timekeeper.C
2025-03-05 08:37:43 +01:00

259 lines
5.7 KiB
C

/*
* PVVMUD a 3D MUD
* Copyright (C) 1998-1999 Programvareverkstedet (pvv@pvv.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "pvvmud.H"
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <iostream.h>
#include "timekeeper.H"
#include "exception.H"
#define mrealloc(ptr, size) ((ptr) ? realloc(ptr, size) : malloc(size))
#define nextsize(size) (((size)==0) ? 20 : ((size)*2))
// Infinite time not defined on all os
#ifndef INFTIM
#define INFTIM -1
#endif
//#define DEBUG_TIMEKEEPER
int CTimeKeeperItem::timeKeeperFD(int event){
return FALSE;
}
int CTimeKeeperItem::timeKeeperSetEvents(int event){
if (m_timeKeeper != NULL){
m_timeKeeper->setEvents(this,event);
return 1;
}
return 0;
}
int CTimeKeeperItem::timeKeeperHB(){
return FALSE;
}
CTimeKeeper::CTimeKeeper() {
hbs=NULL;
num_hbs=0; size_hbs=0;
fds=NULL; timeKeeperFD=NULL;
num_fdns=0; size_fds=0;
mintimeout=INT_MAX;
num=0;
running=0;
setTime();
}
CTimeKeeper::~CTimeKeeper(){
}
void
CTimeKeeper::setTime() {
struct timezone tzp;
gettimeofday(&lasttime, &tzp);
}
int
CTimeKeeper::getTime() {
struct timezone tzp;
struct timeval tv;
gettimeofday(&tv, &tzp);
return ((tv.tv_sec-lasttime.tv_sec)*1000
+(tv.tv_usec-lasttime.tv_usec)/1000);
}
int
CTimeKeeper::addFd(int fd, CTimeKeeperItem * fn, short events) {
fn->timeKeeperSetTimeKeeper(this);
if (size_fds<=num_fdns) {
size_fds = nextsize(size_fds);
fds = (struct pollfd *)mrealloc(fds, size_fds*sizeof(struct pollfd));
timeKeeperFD = (CTimeKeeperItem **)mrealloc(timeKeeperFD,size_fds*sizeof(CTimeKeeperItem*));
if ((fds == NULL) | (timeKeeperFD == NULL)){
throw new CException("Out of memory exception");
}
}
fds[num_fdns].fd = fd;
fds[num_fdns].events = events;
fds[num_fdns].revents = 0;
timeKeeperFD[num_fdns] = fn;
num_fdns++;
return 0;
}
#define MYmemmove(a,b,c) cdebug << "Memmove(Dest= " << a << ",Src= " << b << ",Length= " << c << ");\n"; memmove(a,b,c)
int
CTimeKeeper::rmFd(int fd) {
int i = num_fdns-1;
while (i >= 0){
// for (i=0; i<num_fdns; i++) {
if (fds[i].fd == fd) {
#ifdef DEBUG_TIMEKEEPER
cdebug << "CTimeKeeper::rmFD ( " << fd << " ) at pos : " << i << "\n";
#endif
memmove(&fds[i], &fds[i+1], (DWORD)&fds[num_fdns]-(DWORD)&fds[i+1]);
memmove(&timeKeeperFD[i], &timeKeeperFD[i+1], (DWORD)&timeKeeperFD[num_fdns]-(DWORD)&timeKeeperFD[i+1]);
num_fdns--;
return 1;
}
i--;
}
return 0;
}
int CTimeKeeper::setEvents(CTimeKeeperItem * fn,short events){
int i;
for (i=0; i<num_fdns; i++) {
if (timeKeeperFD[i] == fn) {
fds[i].events = events;
return 1;
}
}
return 0;
}
int
CTimeKeeper::addHeartBeat(int timeout, CTimeKeeperItem * fn) {
int nsize, i;
void *nptr;
if (size_hbs<=num_hbs) {
nsize = nextsize(size_hbs);
nptr = mrealloc(hbs, nsize*sizeof(struct heartbeat));
if (!nptr) return 1;
size_hbs = nsize;
hbs = (struct heartbeat *)nptr;
}
/* round down to nearest 2^n */
for (i=0; timeout &= ~(1<<i) ; i++);
timeout = 1<<i;
hbs[num_hbs].timeout = timeout;
if (timeout < mintimeout) mintimeout=timeout;
hbs[num_hbs].fn = fn;
num_hbs++;
return 0;
}
int
CTimeKeeper::rmHeartBeat(CTimeKeeperItem * fn) {
int i, j;
for (i=0; i<num_hbs; i++) {
if (hbs[i].fn == fn) {
memmove(&hbs[i], &hbs[i+1], &hbs[num_hbs]-&hbs[i+1]);
num_hbs--;
mintimeout = INT_MAX;
for (j=0; j<num_hbs; j++) {
if (hbs[i].timeout < mintimeout)
mintimeout=hbs[i].timeout;
}
return 1;
}
}
return 0;
}
void
CTimeKeeper::stopLoop() {
running=0;
}
void
CTimeKeeper::mainLoop() {
running=1;
while (running) {
poll( ((mintimeout == INT_MAX) ? INFTIM : mintimeout) );
}
}
void
CTimeKeeper::poll(int timeOut) {
int nready, i;
nready = ::poll(fds, num_fdns,timeOut);
// cdebug << "Poll : " << nready << "\n";
#ifdef DEBUG_TIMEKEEPER
if (nready > 0){
cdebug << "CTimeKeeper::poll(...)\n";
cdebug << " nready : " << nready << "\n";
i = num_fdns-1;
while (i >= 0){
cdebug << " fds[" << i << "].fd : " << fds[i].fd << "\n";
cdebug << " fds[" << i << "].events : " << fds[i].events << "\n";
cdebug << " fds[" << i << "].revents : " << fds[i].revents << "\n";
cdebug << " timeKeeperFD[" << i << "].getName() : "
<< timeKeeperFD[i]->getName() << "\n";
i--;
}
}
#endif
// for (i=0; nready > 0 && i < num_fdns; i++) {
i = num_fdns-1; // New
while (i >= 0){ // New
if (fds[i].revents) {
// cdebug << "Event : " << fds[i].revents << "\n";
if (!timeKeeperFD[i]->timeKeeperFD(fds[i].revents)){
rmFd(fds[i].fd);
// i--;
} else {
fds[i].revents=0;
}
// nready--;
}
i--; // New
}
if ( getTime() >= mintimeout ) {
for (i=0; i < num_hbs; i++) {
if (!(num % (hbs[i].timeout/mintimeout))) {
if (!hbs[i].fn->timeKeeperHB()){
rmHeartBeat(hbs[i].fn);
i--;
}
}
}
num++;
setTime();
}
}