Skip to content

Commit d4cb94b

Browse files
Hannes GredlerGIC-de
authored andcommitted
defer freeing empty buckets where it is safe to walk
1 parent ce49944 commit d4cb94b

2 files changed

Lines changed: 37 additions & 17 deletions

File tree

code/common/src/timer.c

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -188,29 +188,17 @@ timer_enqueue_bucket(timer_root_s *root, timer_s *timer, time_t sec, long nsec)
188188
static void
189189
timer_dequeue_bucket(timer_s *timer)
190190
{
191-
timer_root_s *timer_root;
192191
timer_bucket_s *timer_bucket;
193192

194193
timer_bucket = timer->timer_bucket;
195-
timer_root = timer_bucket->timer_root;
196194

197195
CIRCLEQ_REMOVE(&timer_bucket->timer_qhead, timer, timer_qnode);
198196
timer_bucket->timers--;
199197
timer->timer_bucket = NULL;
200198

201-
/* If the last timer of a bucket is gone,
202-
* remove the bucket as well. */
203-
if(!timer_bucket->timers) {
204-
CIRCLEQ_REMOVE(&timer_root->timer_bucket_qhead, timer_bucket, timer_bucket_qnode);
205-
206-
#ifdef BNGBLASTER_TIMER_LOGGING
207-
LOG(TIMER_DETAIL, " Delete timer bucket %lu.%06lus\n",
208-
timer_bucket->sec, timer_bucket->nsec/1000);
209-
#endif
210-
211-
free(timer_bucket);
212-
timer_root->buckets--;
213-
}
199+
/*
200+
* Defer deleting empty buckets to timer_process_changes().
201+
*/
214202
}
215203

216204
static void
@@ -357,11 +345,14 @@ static void
357345
timer_process_changes(timer_root_s *root)
358346
{
359347
timer_s *timer;
360-
timer_bucket_s *timer_bucket;
348+
timer_bucket_s *timer_bucket, *timer_bucket_next;
361349

362350
struct timespec now;
363351
clock_gettime(CLOCK_MONOTONIC, &now);
364352

353+
/*
354+
* First work the chnaged timer list.
355+
*/
365356
while(!CIRCLEQ_EMPTY(&root->timer_change_qhead)) {
366357
timer = CIRCLEQ_FIRST(&root->timer_change_qhead);
367358
timer_bucket = timer->timer_bucket;
@@ -388,6 +379,27 @@ timer_process_changes(timer_root_s *root)
388379
continue;
389380
}
390381
}
382+
383+
/*
384+
* Some buckets may be empty by now.
385+
* Trash them here where it is safe.
386+
*/
387+
CIRCLEQ_FOREACH_SAFE(timer_bucket, &root->timer_bucket_qhead,
388+
timer_bucket_qnode, timer_bucket_next) {
389+
390+
/* If the bucket is empty, remove it. */
391+
if(!timer_bucket->timers) {
392+
CIRCLEQ_REMOVE(&root->timer_bucket_qhead, timer_bucket, timer_bucket_qnode);
393+
394+
#ifdef BNGBLASTER_TIMER_LOGGING
395+
LOG(TIMER_DETAIL, " Delete timer bucket %lu.%06lus\n",
396+
timer_bucket->sec, timer_bucket->nsec/1000);
397+
#endif
398+
399+
free(timer_bucket);
400+
root->buckets--;
401+
}
402+
}
391403
}
392404

393405
/**
@@ -629,4 +641,4 @@ timer_flush_root(timer_root_s *timer_root)
629641
timer_root->gc--;
630642
free(timer);
631643
}
632-
}
644+
}

code/common/src/timer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515
#define MSEC100 100000000UL /* 100 million nanoseconds == 100 milliseconds */
1616
#define SEC 1000000000UL /* 1 billion nanoseconds == 1 second */
1717

18+
#ifndef CIRCLEQ_FOREACH_SAFE
19+
#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
20+
for ((var) = CIRCLEQ_FIRST((head)); \
21+
(var) != (void *)(head) && \
22+
((tvar) = CIRCLEQ_NEXT((var), field), 1); \
23+
(var) = (tvar))
24+
#endif
25+
1826
/* Top level data structure for timers. */
1927
typedef struct timer_root_
2028
{

0 commit comments

Comments
 (0)