Merge pull request #657 from pcercuei/update-lightrec-20220529
[pcsx_rearmed.git] / deps / lightrec / reaper.c
CommitLineData
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
18struct reaper_elm {
19 reap_func_t func;
20 void *data;
21 struct slist_elm slist;
22};
23
24struct 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
32struct 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
58void 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
64int 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
91out_unlock:
92 pthread_mutex_unlock(&reaper->mutex);
93 return ret;
94}
95
98fa08a5
PC
96static bool lightrec_reaper_can_reap(struct reaper *reaper)
97{
98 return !atomic_load_explicit(&reaper->sem, memory_order_relaxed);
99}
100
a59e5536 101void 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
126void lightrec_reaper_pause(struct reaper *reaper)
127{
128 atomic_fetch_add_explicit(&reaper->sem, 1, memory_order_relaxed);
129}
130
131void lightrec_reaper_continue(struct reaper *reaper)
132{
133 atomic_fetch_sub_explicit(&reaper->sem, 1, memory_order_relaxed);
134}