+// SPDX-License-Identifier: LGPL-2.1-or-later
/*
- * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
+ * Copyright (C) 2020-2021 Paul Cercueil <paul@crapouillou.net>
*/
#include "blockcache.h"
#include <errno.h>
#include <pthread.h>
+#include <stdatomic.h>
#include <stdbool.h>
struct reaper_elm {
struct reaper {
struct lightrec_state *state;
pthread_mutex_t mutex;
+ pthread_cond_t cond;
struct slist_elm reap_list;
+
+ bool running;
+ atomic_uint sem;
};
struct reaper *lightrec_reaper_init(struct lightrec_state *state)
}
reaper->state = state;
+ reaper->running = false;
+ reaper->sem = 0;
slist_init(&reaper->reap_list);
ret = pthread_mutex_init(&reaper->mutex, NULL);
if (ret) {
pr_err("Cannot init mutex variable: %d\n", ret);
- lightrec_free(reaper->state, MEM_FOR_LIGHTREC,
- sizeof(*reaper), reaper);
- return NULL;
+ goto err_free_reaper;
+ }
+
+ ret = pthread_cond_init(&reaper->cond, NULL);
+ if (ret) {
+ pr_err("Cannot init cond variable: %d\n", ret);
+ goto err_destroy_mutex;
}
return reaper;
+
+err_destroy_mutex:
+ pthread_mutex_destroy(&reaper->mutex);
+err_free_reaper:
+ lightrec_free(reaper->state, MEM_FOR_LIGHTREC, sizeof(*reaper), reaper);
+ return NULL;
}
void lightrec_reaper_destroy(struct reaper *reaper)
{
+ lightrec_reaper_reap(reaper);
+
+ pthread_cond_destroy(&reaper->cond);
pthread_mutex_destroy(&reaper->mutex);
lightrec_free(reaper->state, MEM_FOR_LIGHTREC, sizeof(*reaper), reaper);
}
return ret;
}
+static bool lightrec_reaper_can_reap(struct reaper *reaper)
+{
+ return !atomic_load_explicit(&reaper->sem, memory_order_relaxed);
+}
+
void lightrec_reaper_reap(struct reaper *reaper)
{
struct reaper_elm *reaper_elm;
pthread_mutex_lock(&reaper->mutex);
- while (!!(elm = slist_first(&reaper->reap_list))) {
+ while (lightrec_reaper_can_reap(reaper) &&
+ !!(elm = slist_first(&reaper->reap_list))) {
slist_remove(&reaper->reap_list, elm);
+ reaper->running = true;
pthread_mutex_unlock(&reaper->mutex);
reaper_elm = container_of(elm, struct reaper_elm, slist);
- (*reaper_elm->func)(reaper_elm->data);
+ (*reaper_elm->func)(reaper->state, reaper_elm->data);
lightrec_free(reaper->state, MEM_FOR_LIGHTREC,
sizeof(*reaper_elm), reaper_elm);
pthread_mutex_lock(&reaper->mutex);
+ reaper->running = false;
+ pthread_cond_broadcast(&reaper->cond);
}
pthread_mutex_unlock(&reaper->mutex);
}
+
+void lightrec_reaper_pause(struct reaper *reaper)
+{
+ atomic_fetch_add_explicit(&reaper->sem, 1, memory_order_relaxed);
+
+ pthread_mutex_lock(&reaper->mutex);
+ while (reaper->running)
+ pthread_cond_wait(&reaper->cond, &reaper->mutex);
+ pthread_mutex_unlock(&reaper->mutex);
+}
+
+void lightrec_reaper_continue(struct reaper *reaper)
+{
+ atomic_fetch_sub_explicit(&reaper->sem, 1, memory_order_relaxed);
+}