* the mark.
*/
+void
+isc_mem_clearwater(isc_mem_t *mctx);
void
isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg,
size_t hiwater, size_t lowater);
*
* When the memory usage of 'mctx' exceeds 'hiwater',
* '(water)(water_arg, #ISC_MEM_HIWATER)' will be called. 'water' needs
- *to call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the
- *state change. 'water' may be called multiple times.
+ * to call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the
+ * state change. 'water' may be called multiple times.
*
* When the usage drops below 'lowater', 'water' will again be called,
- *this time with #ISC_MEM_LOWATER. 'water' need to calls
- *isc_mem_waterack() with #ISC_MEM_LOWATER to acknowledge the change.
+ * this time with #ISC_MEM_LOWATER. 'water' need to calls
+ * isc_mem_waterack() with #ISC_MEM_LOWATER to acknowledge the change.
*
* static void
* water(void *arg, int mark) {
*
* LOCK(&foo->marklock);
* if (foo->mark != mark) {
- * foo->mark = mark;
+ * foo->mark = mark;
* ....
* isc_mem_waterack(foo->mctx, mark);
* }
* UNLOCK(&foo->marklock);
* }
*
- * If 'water' is NULL then 'water_arg', 'hi_water' and 'lo_water' are
- * ignored and the state is reset.
+ * if 'water' is set to NULL, the 'hiwater' and 'lowater' must set to 0, and
+ * high- and low-water processing are disabled for this memory context. There's
+ * a convenient function isc_mem_clearwater().
*
* Requires:
*
- * 'water' is not NULL.
- * hi_water >= lo_water
+ *\li If 'water' is NULL, 'hiwater' and 'lowater' must be set to 0.
+ *\li If 'water' and 'water_arg' have previously been set, they are
+ unchanged.
+ *\li 'hiwater' >= 'lowater'
*/
void
atomic_size_t totalgets;
};
-typedef struct water {
- isc_mem_water_t water;
- void *water_arg;
- size_t hi_water;
- size_t lo_water;
-} water_t;
-
#define MEM_MAGIC ISC_MAGIC('M', 'e', 'm', 'C')
#define VALID_CONTEXT(c) ISC_MAGIC_VALID(c, MEM_MAGIC)
atomic_size_t maxmalloced;
atomic_bool hi_called;
atomic_bool is_overmem;
- atomic_uintptr_t water;
+ isc_mem_water_t water;
+ void *water_arg;
+ atomic_size_t hi_water;
+ atomic_size_t lo_water;
ISC_LIST(isc_mempool_t) pools;
unsigned int poolcnt;
atomic_init(&ctx->maxinuse, 0);
atomic_init(&ctx->malloced, sizeof(*ctx));
atomic_init(&ctx->maxmalloced, sizeof(*ctx));
- atomic_init(&ctx->water, (uintptr_t)NULL);
+ atomic_init(&ctx->hi_water, 0);
+ atomic_init(&ctx->lo_water, 0);
atomic_init(&ctx->hi_called, false);
atomic_init(&ctx->is_overmem, false);
destroy(isc_mem_t *ctx) {
unsigned int i;
size_t malloced;
- water_t *water;
LOCK(&contextslock);
ISC_LIST_UNLINK(contexts, ctx, link);
totallost += isc_mem_inuse(ctx);
UNLOCK(&contextslock);
- water = (water_t *)atomic_exchange(&ctx->water, (uintptr_t)NULL);
- if (water != NULL) {
- sdallocx(water, sizeof(*water), 0);
- decrement_malloced(ctx, sizeof(water_t));
- }
-
ctx->magic = 0;
INSIST(ISC_LIST_EMPTY(ctx->pools));
*ctxp = NULL;
}
-#define CALL_HI_WATER(ctx) \
- { \
- water_t *water = (water_t *)atomic_load_relaxed(&ctx->water); \
- if (water != NULL && hi_water(ctx, water)) { \
- (water->water)(water->water_arg, ISC_MEM_HIWATER); \
- } \
+#define CALL_HI_WATER(ctx) \
+ { \
+ if (ctx->water != NULL && hi_water(ctx)) { \
+ (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); \
+ } \
}
-#define CALL_LO_WATER(ctx) \
- { \
- water_t *water = (water_t *)atomic_load_relaxed(&ctx->water); \
- if ((water != NULL) && lo_water(ctx, water)) { \
- (water->water)(water->water_arg, ISC_MEM_LOWATER); \
- } \
+#define CALL_LO_WATER(ctx) \
+ { \
+ if ((ctx->water != NULL) && lo_water(ctx)) { \
+ (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); \
+ } \
}
static inline bool
-hi_water(isc_mem_t *ctx, water_t *water) {
+hi_water(isc_mem_t *ctx) {
size_t inuse;
size_t maxinuse;
+ size_t hiwater = atomic_load_relaxed(&ctx->hi_water);
- if (water->hi_water == 0) {
+ if (hiwater == 0) {
return (false);
}
inuse = atomic_load_acquire(&ctx->inuse);
- if (inuse <= water->hi_water) {
+ if (inuse <= hiwater) {
return (false);
}
}
static inline bool
-lo_water(isc_mem_t *ctx, water_t *water) {
+lo_water(isc_mem_t *ctx) {
size_t inuse;
+ size_t lowater = atomic_load_relaxed(&ctx->lo_water);
- if (water->lo_water == 0) {
+ if (lowater == 0) {
return (false);
}
inuse = atomic_load_acquire(&ctx->inuse);
- if (inuse >= water->lo_water) {
+ if (inuse >= lowater) {
return (false);
}
return (atomic_load_acquire(&ctx->maxmalloced));
}
+void
+isc_mem_clearwater(isc_mem_t *mctx) {
+ isc_mem_setwater(mctx, NULL, NULL, 0, 0);
+}
+
void
isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg,
size_t hiwater, size_t lowater) {
- water_t *oldwater;
- water_t *newwater = NULL;
+ isc_mem_water_t oldwater;
+ void *oldwater_arg;
REQUIRE(VALID_CONTEXT(ctx));
REQUIRE(hiwater >= lowater);
- if (water != NULL) {
- newwater = mallocx(sizeof(*newwater), 0);
- increment_malloced(ctx, sizeof(*newwater));
+ oldwater = ctx->water;
+ oldwater_arg = ctx->water_arg;
- *newwater = (water_t){
- .water = water,
- .water_arg = water_arg,
- .hi_water = hiwater,
- .lo_water = lowater,
- };
+ /* No water was set and new water is also NULL */
+ if (oldwater == NULL && water == NULL) {
+ return;
}
- oldwater = (water_t *)atomic_exchange(&ctx->water, (uintptr_t)newwater);
+ /* The water function is being set for the first time */
if (oldwater == NULL) {
+ REQUIRE(water != NULL && lowater > 0);
+
+ INSIST(atomic_load(&ctx->hi_water) == 0);
+ INSIST(atomic_load(&ctx->lo_water) == 0);
+
+ ctx->water = water;
+ ctx->water_arg = water_arg;
+ atomic_store(&ctx->hi_water, hiwater);
+ atomic_store(&ctx->lo_water, lowater);
+
return;
}
- INSIST(oldwater->water != NULL);
+ REQUIRE((water == oldwater && water_arg == oldwater_arg) ||
+ (water == NULL && water_arg == NULL && hiwater == 0));
+
+ atomic_store(&ctx->hi_water, hiwater);
+ atomic_store(&ctx->lo_water, lowater);
if (atomic_load_acquire(&ctx->hi_called) &&
- (oldwater->water != water || oldwater->water_arg != water_arg ||
- atomic_load_acquire(&ctx->inuse) < lowater || lowater == 0U))
+ (atomic_load_acquire(&ctx->inuse) < lowater || lowater == 0U))
{
- (oldwater->water)(oldwater->water_arg, ISC_MEM_LOWATER);
+ (oldwater)(oldwater_arg, ISC_MEM_LOWATER);
}
-
- decrement_malloced(ctx, sizeof(*oldwater));
- sdallocx(oldwater, sizeof(*oldwater), 0);
}
bool
REQUIRE(VALID_CONTEXT(ctx));
int xmlrc;
- water_t *water;
MCTXLOCK(ctx);
summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "hiwater"));
- water = (water_t *)atomic_load_relaxed(&ctx->water);
TRY0(xmlTextWriterWriteFormatString(
writer, "%" PRIu64 "",
- (water != NULL) ? (uint64_t)water->hi_water : 0));
+ (uint64_t)atomic_load_relaxed(&ctx->hi_water)));
TRY0(xmlTextWriterEndElement(writer)); /* hiwater */
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "lowater"));
TRY0(xmlTextWriterWriteFormatString(
writer, "%" PRIu64 "",
- (water != NULL) ? (uint64_t)water->lo_water : 0));
+ (uint64_t)atomic_load_relaxed(&ctx->lo_water)));
TRY0(xmlTextWriterEndElement(writer)); /* lowater */
TRY0(xmlTextWriterEndElement(writer)); /* context */
json_object *ctxobj, *obj;
char buf[1024];
- water_t *water;
MCTXLOCK(ctx);
summary->contextsize += ctx->poolcnt * sizeof(isc_mempool_t);
- water = (water_t *)atomic_load_relaxed(&ctx->water);
- obj = json_object_new_int64((water != NULL) ? water->hi_water : 0);
+ obj = json_object_new_int64(atomic_load_relaxed(&ctx->hi_water));
CHECKMEM(obj);
json_object_object_add(ctxobj, "hiwater", obj);
- obj = json_object_new_int64((water != NULL) ? water->lo_water : 0);
+ obj = json_object_new_int64(atomic_load_relaxed(&ctx->lo_water));
CHECKMEM(obj);
json_object_object_add(ctxobj, "lowater", obj);