Commit | Line | Data |
---|---|---|
98fa08a5 | 1 | // SPDX-License-Identifier: LGPL-2.1-or-later |
a59e5536 | 2 | /* |
98fa08a5 | 3 | * Copyright (C) 2020-2021 Paul Cercueil <paul@crapouillou.net> |
a59e5536 | 4 | */ |
5 | ||
6 | #include "blockcache.h" | |
7 | #include "debug.h" | |
8 | #include "lightrec-private.h" | |
9 | #include "memmanager.h" | |
10 | #include "slist.h" | |
11 | #include "reaper.h" | |
12 | ||
13 | #include <errno.h> | |
14 | #include <pthread.h> | |
98fa08a5 | 15 | #include <stdatomic.h> |
a59e5536 | 16 | #include <stdbool.h> |
17 | ||
18 | struct reaper_elm { | |
19 | reap_func_t func; | |
20 | void *data; | |
21 | struct slist_elm slist; | |
22 | }; | |
23 | ||
24 | struct reaper { | |
25 | struct lightrec_state *state; | |
26 | pthread_mutex_t mutex; | |
27 | struct slist_elm reap_list; | |
98fa08a5 PC |
28 | |
29 | atomic_uint sem; | |
a59e5536 | 30 | }; |
31 | ||
32 | struct reaper *lightrec_reaper_init(struct lightrec_state *state) | |
33 | { | |
34 | struct reaper *reaper; | |
35 | int ret; | |
36 | ||
37 | reaper = lightrec_malloc(state, MEM_FOR_LIGHTREC, sizeof(*reaper)); | |
38 | if (!reaper) { | |
39 | pr_err("Cannot create reaper: Out of memory\n"); | |
40 | return NULL; | |
41 | } | |
42 | ||
43 | reaper->state = state; | |
98fa08a5 | 44 | reaper->sem = 0; |
a59e5536 | 45 | slist_init(&reaper->reap_list); |
46 | ||
47 | ret = pthread_mutex_init(&reaper->mutex, NULL); | |
48 | if (ret) { | |
49 | pr_err("Cannot init mutex variable: %d\n", ret); | |
50 | lightrec_free(reaper->state, MEM_FOR_LIGHTREC, | |
51 | sizeof(*reaper), reaper); | |
52 | return NULL; | |
53 | } | |
54 | ||
55 | return reaper; | |
56 | } | |
57 | ||
58 | void lightrec_reaper_destroy(struct reaper *reaper) | |
59 | { | |
60 | pthread_mutex_destroy(&reaper->mutex); | |
61 | lightrec_free(reaper->state, MEM_FOR_LIGHTREC, sizeof(*reaper), reaper); | |
62 | } | |
63 | ||
64 | int lightrec_reaper_add(struct reaper *reaper, reap_func_t f, void *data) | |
65 | { | |
66 | struct reaper_elm *reaper_elm; | |
67 | struct slist_elm *elm; | |
68 | int ret = 0; | |
69 | ||
70 | pthread_mutex_lock(&reaper->mutex); | |
71 | ||
72 | for (elm = reaper->reap_list.next; elm; elm = elm->next) { | |
73 | reaper_elm = container_of(elm, struct reaper_elm, slist); | |
74 | ||
75 | if (reaper_elm->data == data) | |
76 | goto out_unlock; | |
77 | } | |
78 | ||
79 | reaper_elm = lightrec_malloc(reaper->state, MEM_FOR_LIGHTREC, | |
80 | sizeof(*reaper_elm)); | |
81 | if (!reaper_elm) { | |
82 | pr_err("Cannot add reaper entry: Out of memory\n"); | |
83 | ret = -ENOMEM; | |
84 | goto out_unlock; | |
85 | } | |
86 | ||
87 | reaper_elm->func = f; | |
88 | reaper_elm->data = data; | |
89 | slist_append(&reaper->reap_list, &reaper_elm->slist); | |
90 | ||
91 | out_unlock: | |
92 | pthread_mutex_unlock(&reaper->mutex); | |
93 | return ret; | |
94 | } | |
95 | ||
98fa08a5 PC |
96 | static bool lightrec_reaper_can_reap(struct reaper *reaper) |
97 | { | |
98 | return !atomic_load_explicit(&reaper->sem, memory_order_relaxed); | |
99 | } | |
100 | ||
a59e5536 | 101 | void lightrec_reaper_reap(struct reaper *reaper) |
102 | { | |
103 | struct reaper_elm *reaper_elm; | |
104 | struct slist_elm *elm; | |
105 | ||
106 | pthread_mutex_lock(&reaper->mutex); | |
107 | ||
98fa08a5 PC |
108 | while (lightrec_reaper_can_reap(reaper) && |
109 | !!(elm = slist_first(&reaper->reap_list))) { | |
a59e5536 | 110 | slist_remove(&reaper->reap_list, elm); |
111 | pthread_mutex_unlock(&reaper->mutex); | |
112 | ||
113 | reaper_elm = container_of(elm, struct reaper_elm, slist); | |
114 | ||
98fa08a5 | 115 | (*reaper_elm->func)(reaper->state, reaper_elm->data); |
a59e5536 | 116 | |
117 | lightrec_free(reaper->state, MEM_FOR_LIGHTREC, | |
118 | sizeof(*reaper_elm), reaper_elm); | |
119 | ||
120 | pthread_mutex_lock(&reaper->mutex); | |
121 | } | |
122 | ||
123 | pthread_mutex_unlock(&reaper->mutex); | |
124 | } | |
98fa08a5 PC |
125 | |
126 | void lightrec_reaper_pause(struct reaper *reaper) | |
127 | { | |
128 | atomic_fetch_add_explicit(&reaper->sem, 1, memory_order_relaxed); | |
129 | } | |
130 | ||
131 | void lightrec_reaper_continue(struct reaper *reaper) | |
132 | { | |
133 | atomic_fetch_sub_explicit(&reaper->sem, 1, memory_order_relaxed); | |
134 | } |