391
typedef struct {
392
ThrottleGroupMember *tgm;
393
ThrottleDirection direction;
394
+ bool reset_timer_armed;
395
} RestartData;
396
397
static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
404
bool empty_queue;
405
406
qemu_mutex_lock(&tg->lock);
407
+ if (data->reset_timer_armed) {
408
+ tg->any_timer_armed[direction] = false;
409
+ }
410
empty_queue = !throttle_group_co_restart_queue(tgm, direction);
411
412
/* If the request queue was empty then we have to take care of
423
}
424
425
static void throttle_group_restart_queue(ThrottleGroupMember *tgm,
422
- ThrottleDirection direction)
426
+ ThrottleDirection direction,
427
+ bool reset_timer_armed)
428
{
429
Coroutine *co;
430
RestartData *rd = g_new0(RestartData, 1);
431
432
rd->tgm = tgm;
433
rd->direction = direction;
434
+ rd->reset_timer_armed = reset_timer_armed;
435
430
- /* This function is called when a timer is fired or when
431
- * throttle_group_restart_tgm() is called. Either way, there can
436
+ /* If reset_timer_armed is set then this means that this function
437
+ * was called when a timer was fired (either from timer_cb() or
438
+ * from throttle_group_restart_tgm()). In this case there can
439
* be no timer pending on this tgm at this point */
433
- assert(!timer_pending(tgm->throttle_timers.timers[direction]));
440
+ if (reset_timer_armed) {
441
+ assert(!timer_pending(tgm->throttle_timers.timers[direction]));
442
+ }
443
444
qatomic_inc(&tgm->restart_pending);
445
453
454
if (tgm->throttle_state) {
455
for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
447
- QEMUTimer *t = tgm->throttle_timers.timers[dir];
456
+ QEMUTimer *t;
457
+ ThrottleState *ts = tgm->throttle_state;
458
+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
459
+ bool reset_timer_armed;
460
+
461
+ /*
462
+ * This function restarts the tgm's queue immediately.
463
+ * This is used for example for callers to drain all requests.
464
+ * There are three different scenarios depending on whether
465
+ * a timer is armed for this tg and which tgm owns the timer.
466
+ */
467
+
468
+ qemu_mutex_lock(&tg->lock);
469
+
470
+ t = tgm->throttle_timers.timers[dir];
471
if (timer_pending(t)) {
449
- /* If there's a pending timer on this tgm, fire it now */
472
+ /*
473
+ * Case 1: this tgm has a pending timer.
474
+ * We can fire the timer immediately.
475
+ */
476
timer_del(t);
451
- timer_cb(tgm, dir);
477
+ reset_timer_armed = true;
478
+ } else if (tg->any_timer_armed[dir]) {
479
+ /*
480
+ * Case 2: another tgm has a pending timer.
481
+ * In this case we can still restart the queue but we
482
+ * have to leave any_timer_armed untouched so the
483
+ * other tgm's timer is not disrupted.
484
+ */
485
+ reset_timer_armed = false;
486
} else {
453
- /* Else run the next request from the queue manually */
454
- throttle_group_restart_queue(tgm, dir);
487
+ /*
488
+ * Case 3: there is no timer set for this group.
489
+ * Here we can simulate a timer that fires immediately,
490
+ * so the queue is restarted but no other thread
491
+ * can arm a timer in the meantime.
492
+ */
493
+ tg->any_timer_armed[dir] = true;
494
+ reset_timer_armed = true;
495
}
496
+
497
+ qemu_mutex_unlock(&tg->lock);
498
+
499
+ throttle_group_restart_queue(tgm, dir, reset_timer_armed);
500
}
501
}
502
}
543
*/
544
static void timer_cb(ThrottleGroupMember *tgm, ThrottleDirection direction)
545
{
502
- ThrottleState *ts = tgm->throttle_state;
503
- ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
504
-
505
- /* The timer has just been fired, so we can update the flag */
506
- qemu_mutex_lock(&tg->lock);
507
- tg->any_timer_armed[direction] = false;
508
- qemu_mutex_unlock(&tg->lock);
509
-
510
- /* Run the request that was waiting for this timer */
511
- throttle_group_restart_queue(tgm, direction);
546
+ /*
547
+ * Run the request that was waiting for this timer.
548
+ * tg->any_timer_armed needs to be cleared, but we'll do it later
549
+ * when the queue is restarted in order to prevent another thread
550
+ * from arming the timer before that.
551
+ */
552
+ throttle_group_restart_queue(tgm, direction, true);
553
}
554
555
static void read_timer_cb(void *opaque)