haiku/headers/private/kernel/load_tracking.h
Michael Lotz da30fdf96a kernel: Fix overflow in load tracking for very large deltas.
The scheduler uses the load tracking logic to compute the load of
threads to be enqueued into the run queue. The time delta between the
last enqueue and the next enqueue may grow very large for threads
that mostly wait on conditions. In such cases the int "n" period count
variable would become too small and wrap around, leading to an
assertion failure.

For this to happen, the thread in question would have to have slept for
at least ~25 days and then wake up. Threads often affected would be ones
waiting for some other process to end, for example shell threads waiting
for a long running process to exit.

Fixes #13558.
2018-01-05 22:48:56 +01:00

58 lines
1.1 KiB
C

/*
* Copyright 2013 Paweł Dziepak, pdziepak@quarnos.org.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_LOAD_TRACKING_H
#define _KERNEL_LOAD_TRACKING_H
#include <OS.h>
const int32 kMaxLoad = 1000;
const bigtime_t kLoadMeasureInterval = 1000;
const bigtime_t kIntervalInaccuracy = kLoadMeasureInterval / 4;
static inline int32
compute_load(bigtime_t& measureTime, bigtime_t& measureActiveTime, int32& load,
bigtime_t now)
{
if (measureTime == 0) {
measureTime = now;
return -1;
}
bigtime_t deltaTime = now - measureTime;
if (deltaTime < kLoadMeasureInterval)
return -1;
int32 oldLoad = load;
ASSERT(oldLoad >= 0 && oldLoad <= kMaxLoad);
int32 newLoad = measureActiveTime * kMaxLoad;
newLoad /= max_c(deltaTime, 1);
newLoad = max_c(min_c(newLoad, kMaxLoad), 0);
measureActiveTime = 0;
measureTime = now;
deltaTime += kIntervalInaccuracy;
bigtime_t n = deltaTime / kLoadMeasureInterval;
ASSERT(n > 0);
if (n > 10)
load = newLoad;
else {
newLoad *= (1 << n) - 1;
load = (load + newLoad) / (1 << n);
ASSERT(load >= 0 && load <= kMaxLoad);
}
return oldLoad;
}
#endif // _KERNEL_LOAD_TRACKING_H