Another fix to avoid timer starvation by X events.
- Thanks to Mark Bowyer for help to sort this out. Change timers to use absolute time. SVN revision: 19657
This commit is contained in:
parent
cf34dce748
commit
2dd6d5f12b
5
src/E.h
5
src/E.h
|
@ -579,12 +579,11 @@ EMode;
|
||||||
typedef struct _qentry
|
typedef struct _qentry
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
double in_time;
|
double at_time;
|
||||||
void (*func) (int val, void *data);
|
void (*func) (int val, void *data);
|
||||||
struct _qentry *next;
|
struct _qentry *next;
|
||||||
int runtime_val;
|
int runtime_val;
|
||||||
void *runtime_data;
|
void *runtime_data;
|
||||||
char just_added;
|
|
||||||
}
|
}
|
||||||
Qentry;
|
Qentry;
|
||||||
|
|
||||||
|
@ -742,7 +741,7 @@ void EventDebugSet(unsigned int type, int value);
|
||||||
#define EventDebugSet(type, value)
|
#define EventDebugSet(type, value)
|
||||||
#endif
|
#endif
|
||||||
void EventsInit(void);
|
void EventsInit(void);
|
||||||
void WaitEvent(void);
|
void EventsMain(void);
|
||||||
void EventDebugInit(const char *s);
|
void EventDebugInit(const char *s);
|
||||||
void EventShow(const XEvent * ev);
|
void EventShow(const XEvent * ev);
|
||||||
|
|
||||||
|
|
166
src/events.c
166
src/events.c
|
@ -533,123 +533,111 @@ EventsProcess(XEvent ** evq_p, int *evq_n, int *evq_f)
|
||||||
* events from the X server are interpreted, timer events are inserted, etc
|
* events from the X server are interpreted, timer events are inserted, etc
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
WaitEvent(void)
|
EventsMain(void)
|
||||||
{
|
{
|
||||||
static int evq_alloc = 0;
|
static int evq_alloc = 0;
|
||||||
static int evq_fetch = 0;
|
static int evq_fetch = 0;
|
||||||
static XEvent *evq_ptr = NULL;
|
static XEvent *evq_ptr = NULL;
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
struct timeval tval;
|
struct timeval tval;
|
||||||
static struct timeval tval_last = { 0, 0 };
|
double time1, time2, dt;
|
||||||
double time1, time2;
|
|
||||||
Qentry *qe;
|
Qentry *qe;
|
||||||
int count, pcount, pfetch;
|
int count, pfetch;
|
||||||
int fdsize;
|
int fdsize;
|
||||||
int xfd, smfd;
|
int xfd, smfd;
|
||||||
|
|
||||||
pcount = pfetch = 0;
|
time1 = GetTime();
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
pfetch = 0;
|
||||||
count = EventsProcess(&evq_ptr, &evq_alloc, &pfetch);
|
count = EventsProcess(&evq_ptr, &evq_alloc, &pfetch);
|
||||||
|
|
||||||
if (count > pcount)
|
|
||||||
pcount = count;
|
|
||||||
|
|
||||||
if (XPending(disp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (EventDebug(EDBUG_TYPE_EVENTS))
|
if (EventDebug(EDBUG_TYPE_EVENTS))
|
||||||
Eprintf("WaitEvent - Idlers\n");
|
Eprintf("EventsMain - Idlers\n");
|
||||||
DialogsCheckUpdate(); /* FIXME - Shouldn't be here */
|
DialogsCheckUpdate(); /* FIXME - Shouldn't be here */
|
||||||
ModulesSignal(ESIGNAL_IDLE, NULL);
|
ModulesSignal(ESIGNAL_IDLE, NULL);
|
||||||
|
|
||||||
if (!XPending(disp))
|
if (pfetch)
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pfetch)
|
|
||||||
{
|
|
||||||
evq_fetch =
|
|
||||||
(pfetch > evq_fetch) ? pfetch : (3 * evq_fetch + pfetch) / 4;
|
|
||||||
if (EventDebug(EDBUG_TYPE_EVENTS))
|
|
||||||
Eprintf("WaitEvent - Alloc/fetch/pfetch/peak=%d/%d/%d/%d)\n",
|
|
||||||
evq_alloc, evq_fetch, pfetch, pcount);
|
|
||||||
if ((evq_ptr) && ((evq_alloc - evq_fetch) > 64))
|
|
||||||
{
|
{
|
||||||
evq_alloc = 0;
|
evq_fetch =
|
||||||
Efree(evq_ptr);
|
(pfetch > evq_fetch) ? pfetch : (3 * evq_fetch + pfetch) / 4;
|
||||||
evq_ptr = NULL;
|
if (EventDebug(EDBUG_TYPE_EVENTS))
|
||||||
|
Eprintf("EventsMain - Alloc/fetch/pfetch/peak=%d/%d/%d/%d)\n",
|
||||||
|
evq_alloc, evq_fetch, pfetch, count);
|
||||||
|
if ((evq_ptr) && ((evq_alloc - evq_fetch) > 64))
|
||||||
|
{
|
||||||
|
evq_alloc = 0;
|
||||||
|
Efree(evq_ptr);
|
||||||
|
evq_ptr = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
xfd = ConnectionNumber(disp);
|
xfd = ConnectionNumber(disp);
|
||||||
FD_SET(xfd, &fdset);
|
FD_SET(xfd, &fdset);
|
||||||
smfd = GetSMfd();
|
smfd = GetSMfd();
|
||||||
if (smfd >= 0)
|
if (smfd >= 0)
|
||||||
FD_SET(smfd, &fdset);
|
FD_SET(smfd, &fdset);
|
||||||
fdsize = MAX(xfd, smfd) + 1;
|
fdsize = MAX(xfd, smfd) + 1;
|
||||||
|
|
||||||
/* First time */
|
/* time2 = current time */
|
||||||
if ((tval_last.tv_sec == 0) && (tval_last.tv_usec == 0))
|
time2 = GetTime();
|
||||||
gettimeofday(&tval_last, NULL);
|
dt = time2 - time1;
|
||||||
/* time1 = time we last were here */
|
time1 = time2;
|
||||||
time1 = ((double)tval_last.tv_sec) + (((double)tval_last.tv_usec) / 1000000);
|
if (dt < 0.0)
|
||||||
|
dt = 0.0;
|
||||||
|
/* dt = time spent since we last were here */
|
||||||
|
|
||||||
/* time2 = current time */
|
qe = GetHeadTimerQueue();
|
||||||
gettimeofday(&tval, NULL);
|
if (qe)
|
||||||
time2 = ((double)tval.tv_sec) + (((double)tval.tv_usec) / 1000000);
|
|
||||||
time2 -= time1;
|
|
||||||
if (time2 < 0.0)
|
|
||||||
time2 = 0.0;
|
|
||||||
/* time2 = time spent since we last were here */
|
|
||||||
|
|
||||||
tval_last.tv_sec = tval.tv_sec;
|
|
||||||
tval_last.tv_usec = tval.tv_usec;
|
|
||||||
|
|
||||||
qe = GetHeadTimerQueue();
|
|
||||||
if (qe)
|
|
||||||
{
|
|
||||||
if (qe->just_added)
|
|
||||||
{
|
{
|
||||||
qe->just_added = 0;
|
count = 0;
|
||||||
time1 = qe->in_time;
|
time2 = qe->at_time - time2;
|
||||||
|
if (time2 < 0.0)
|
||||||
|
time2 = 0.0;
|
||||||
|
if (time2 <= 0.0)
|
||||||
|
goto do_timer;
|
||||||
|
if (XPending(disp))
|
||||||
|
continue;
|
||||||
|
tval.tv_sec = (long)time2;
|
||||||
|
tval.tv_usec = (long)((time2 - ((double)tval.tv_sec)) * 1000000);
|
||||||
|
count = select(fdsize, &fdset, NULL, NULL, &tval);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
time1 = qe->in_time - time2;
|
if (XPending(disp))
|
||||||
if (time1 < 0.0)
|
continue;
|
||||||
time1 = 0.0;
|
count = select(fdsize, &fdset, NULL, NULL, NULL);
|
||||||
qe->in_time = time1;
|
|
||||||
}
|
}
|
||||||
tval.tv_sec = (long)time1;
|
|
||||||
tval.tv_usec = (long)((time1 - ((double)tval.tv_sec)) * 1000000);
|
|
||||||
count = select(fdsize, &fdset, NULL, NULL, &tval);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
count = select(fdsize, &fdset, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (EventDebug(EDBUG_TYPE_EVENTS))
|
|
||||||
Eprintf
|
|
||||||
("WaitEvent - count=%d xfd=%d:%d smfd=%d:%d qe=%p time1=%lf time2=%lf\n",
|
|
||||||
count, xfd, FD_ISSET(xfd, &fdset), smfd,
|
|
||||||
(smfd >= 0) ? FD_ISSET(smfd, &fdset) : 0, qe, time1, time2);
|
|
||||||
|
|
||||||
if (count < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((smfd >= 0) && (count > 0) && (FD_ISSET(smfd, &fdset)))
|
|
||||||
{
|
|
||||||
if (EventDebug(EDBUG_TYPE_EVENTS))
|
if (EventDebug(EDBUG_TYPE_EVENTS))
|
||||||
Eprintf("WaitEvent - ICE\n");
|
Eprintf
|
||||||
ProcessICEMSGS();
|
("EventsMain - count=%d xfd=%d:%d smfd=%d:%d qe=%p dt=%lf time2=%lf\n",
|
||||||
}
|
count, xfd, FD_ISSET(xfd, &fdset), smfd,
|
||||||
|
(smfd >= 0) ? FD_ISSET(smfd, &fdset) : 0, qe, dt, time2);
|
||||||
|
|
||||||
if (qe && (count == 0 || time1 <= 0.0))
|
if (count < 0)
|
||||||
{
|
continue;
|
||||||
if (EventDebug(EDBUG_TYPE_EVENTS))
|
|
||||||
Eprintf("WaitEvent - Timers (%s)\n", qe->name);
|
if (count > 0)
|
||||||
HandleTimerEvent();
|
{
|
||||||
|
if ((smfd >= 0) && (FD_ISSET(smfd, &fdset)))
|
||||||
|
{
|
||||||
|
if (EventDebug(EDBUG_TYPE_EVENTS))
|
||||||
|
Eprintf("EventsMain - ICE\n");
|
||||||
|
ProcessICEMSGS();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_timer:
|
||||||
|
if (qe)
|
||||||
|
{
|
||||||
|
if (EventDebug(EDBUG_TYPE_EVENTS))
|
||||||
|
Eprintf("EventsMain - Timers (%s)\n", qe->name);
|
||||||
|
HandleTimerEvent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -906,7 +894,11 @@ EventShow(const XEvent * ev)
|
||||||
Eprintf("%#08lx EV-%s win=%#lx\n", ser, name, win);
|
Eprintf("%#08lx EV-%s win=%#lx\n", ser, name, win);
|
||||||
break;
|
break;
|
||||||
case EX_EVENT_SHAPE_NOTIFY:
|
case EX_EVENT_SHAPE_NOTIFY:
|
||||||
Eprintf("%#08lx EV-%s win=%#lx\n", ser, name, win);
|
#define se ((XShapeEvent *)ev)
|
||||||
|
Eprintf("%#08lx EV-%s win=%#lx kind=%d shaped=%d %d,%d %dx%d\n",
|
||||||
|
ser, name, win, se->kind, se->shaped,
|
||||||
|
se->x, se->y, se->width, se->height);
|
||||||
|
#undef se
|
||||||
break;
|
break;
|
||||||
#if USE_XRANDR
|
#if USE_XRANDR
|
||||||
case EX_EVENT_SCREEN_CHANGE_NOTIFY:
|
case EX_EVENT_SCREEN_CHANGE_NOTIFY:
|
||||||
|
|
|
@ -304,8 +304,7 @@ main(int argc, char **argv)
|
||||||
autosave();
|
autosave();
|
||||||
|
|
||||||
/* The primary event loop */
|
/* The primary event loop */
|
||||||
for (;;)
|
EventsMain();
|
||||||
WaitEvent();
|
|
||||||
|
|
||||||
/* Of course, we should NEVER get to this point */
|
/* Of course, we should NEVER get to this point */
|
||||||
|
|
||||||
|
|
99
src/timers.c
99
src/timers.c
|
@ -39,72 +39,40 @@ DoIn(const char *name, double in_time, void (*func) (int val, void *data),
|
||||||
int runtime_val, void *runtime_data)
|
int runtime_val, void *runtime_data)
|
||||||
{
|
{
|
||||||
Qentry *qe, *ptr, *pptr;
|
Qentry *qe, *ptr, *pptr;
|
||||||
double tally;
|
|
||||||
|
|
||||||
RemoveTimerEvent(name);
|
RemoveTimerEvent(name);
|
||||||
qe = Emalloc(sizeof(Qentry));
|
qe = Emalloc(sizeof(Qentry));
|
||||||
if (!qe)
|
if (!qe)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (EventDebug(EDBUG_TYPE_EVENTS))
|
||||||
|
Eprintf("DoIn %8.3f: %s\n", in_time, name);
|
||||||
|
|
||||||
qe->name = Estrdup(name);
|
qe->name = Estrdup(name);
|
||||||
qe->func = func;
|
qe->func = func;
|
||||||
qe->next = NULL;
|
qe->at_time = GetTime() + in_time;
|
||||||
qe->in_time = in_time;
|
|
||||||
qe->runtime_val = runtime_val;
|
qe->runtime_val = runtime_val;
|
||||||
qe->runtime_data = runtime_data;
|
qe->runtime_data = runtime_data;
|
||||||
qe->just_added = 1;
|
|
||||||
|
|
||||||
/* if there is no queue it becomes the queue */
|
/* if there is no queue it becomes the queue */
|
||||||
if (!q_first)
|
if (!q_first)
|
||||||
q_first = qe;
|
{
|
||||||
|
q_first = qe;
|
||||||
|
qe->next = NULL;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pptr = NULL;
|
pptr = NULL;
|
||||||
ptr = q_first;
|
for (ptr = q_first; ptr; pptr = ptr, ptr = ptr->next)
|
||||||
tally = 0.0;
|
|
||||||
/* scan along the queue from start until sum of all timer intervals */
|
|
||||||
/* greater than time then insert before last entry found (since it */
|
|
||||||
/* managed to push the tally over past the end of out new timer) */
|
|
||||||
while (ptr)
|
|
||||||
{
|
{
|
||||||
/* add to tally */
|
if (ptr->at_time > qe->at_time)
|
||||||
tally += ptr->in_time;
|
break;
|
||||||
/* if this entry is after our new one add before this entry */
|
|
||||||
if (tally > in_time)
|
|
||||||
{
|
|
||||||
/* number of seconds of stuff to do before the new entry */
|
|
||||||
tally -= ptr->in_time;
|
|
||||||
/* if the previous pointer exists then add like normal */
|
|
||||||
qe->next = ptr;
|
|
||||||
if (pptr)
|
|
||||||
{
|
|
||||||
pptr->next = qe;
|
|
||||||
}
|
|
||||||
/* no previous - must have to add as first in list */
|
|
||||||
else
|
|
||||||
q_first = qe;
|
|
||||||
/* subtract "stuff to do before" as timers are relative */
|
|
||||||
qe->in_time -= tally;
|
|
||||||
/* if there is a timer after this one, subtract the time this
|
|
||||||
* new timer has to wait from it since its inserted into the
|
|
||||||
* time span here
|
|
||||||
*/
|
|
||||||
if (qe->next)
|
|
||||||
qe->next->in_time -= qe->in_time;
|
|
||||||
/* we're done */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pptr = ptr;
|
|
||||||
ptr = ptr->next;
|
|
||||||
/* keep going through the list till we reach the end */
|
|
||||||
}
|
}
|
||||||
/* add to end of list */
|
|
||||||
if (pptr)
|
if (pptr)
|
||||||
pptr->next = qe;
|
pptr->next = qe;
|
||||||
else
|
else
|
||||||
q_first = qe;
|
q_first = qe;
|
||||||
|
qe->next = ptr;
|
||||||
qe->in_time -= tally;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +96,7 @@ HandleTimerEvent(void)
|
||||||
/* remove it */
|
/* remove it */
|
||||||
q_first = q_first->next;
|
q_first = q_first->next;
|
||||||
/* run this callback */
|
/* run this callback */
|
||||||
(*(qe->func)) (qe->runtime_val, qe->runtime_data);
|
qe->func(qe->runtime_val, qe->runtime_data);
|
||||||
/* free the timer */
|
/* free the timer */
|
||||||
if (qe->name)
|
if (qe->name)
|
||||||
Efree(qe->name);
|
Efree(qe->name);
|
||||||
|
@ -142,33 +110,24 @@ RemoveTimerEvent(const char *name)
|
||||||
Qentry *qe, *ptr, *pptr;
|
Qentry *qe, *ptr, *pptr;
|
||||||
|
|
||||||
pptr = NULL;
|
pptr = NULL;
|
||||||
ptr = q_first;
|
for (ptr = q_first; ptr; pptr = ptr, ptr = ptr->next)
|
||||||
/* hunt through the queue */
|
|
||||||
while (ptr)
|
|
||||||
{
|
{
|
||||||
/* if the name of a timer matches */
|
|
||||||
qe = ptr;
|
qe = ptr;
|
||||||
if (!strcmp(qe->name, name))
|
if (strcmp(qe->name, name))
|
||||||
{
|
continue;
|
||||||
/* remove it form the queue */
|
|
||||||
if (pptr)
|
/* Match - remove it from the queue */
|
||||||
pptr->next = qe->next;
|
if (pptr)
|
||||||
else
|
pptr->next = qe->next;
|
||||||
q_first = qe->next;
|
else
|
||||||
/* increase the time of the next timer accordingly */
|
q_first = qe->next;
|
||||||
if (qe->next)
|
/* free it */
|
||||||
qe->next->in_time += qe->in_time;
|
if (qe->name)
|
||||||
/* free it */
|
Efree(qe->name);
|
||||||
if (qe->name)
|
if (qe)
|
||||||
Efree(qe->name);
|
Efree(qe);
|
||||||
if (qe)
|
/* done */
|
||||||
Efree(qe);
|
return 1;
|
||||||
/* done */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
pptr = ptr;
|
|
||||||
ptr = ptr->next;
|
|
||||||
/* keep going through the queue */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue