libretro: direct fb access requires duping support
[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;
ba3814c1 27 pthread_cond_t cond;
a59e5536 28 struct slist_elm reap_list;
98fa08a5 29
ba3814c1 30 bool running;
98fa08a5 31 atomic_uint sem;
a59e5536 32};
33
34struct reaper *lightrec_reaper_init(struct lightrec_state *state)
35{
36 struct reaper *reaper;
37 int ret;
38
39 reaper = lightrec_malloc(state, MEM_FOR_LIGHTREC, sizeof(*reaper));
40 if (!reaper) {
41 pr_err("Cannot create reaper: Out of memory\n");
42 return NULL;
43 }
44
45 reaper->state = state;
ba3814c1 46 reaper->running = false;
98fa08a5 47 reaper->sem = 0;
a59e5536 48 slist_init(&reaper->reap_list);
49
50 ret = pthread_mutex_init(&reaper->mutex, NULL);
51 if (ret) {
52 pr_err("Cannot init mutex variable: %d\n", ret);
ba3814c1
PC
53 goto err_free_reaper;
54 }
55
56 ret = pthread_cond_init(&reaper->cond, NULL);
57 if (ret) {
58 pr_err("Cannot init cond variable: %d\n", ret);
59 goto err_destroy_mutex;
a59e5536 60 }
61
62 return reaper;
ba3814c1
PC
63
64err_destroy_mutex:
65 pthread_mutex_destroy(&reaper->mutex);
66err_free_reaper:
67 lightrec_free(reaper->state, MEM_FOR_LIGHTREC, sizeof(*reaper), reaper);
68 return NULL;
a59e5536 69}
70
71void lightrec_reaper_destroy(struct reaper *reaper)
72{
ba3814c1
PC
73 lightrec_reaper_reap(reaper);
74
75 pthread_cond_destroy(&reaper->cond);
a59e5536 76 pthread_mutex_destroy(&reaper->mutex);
77 lightrec_free(reaper->state, MEM_FOR_LIGHTREC, sizeof(*reaper), reaper);
78}
79
80int lightrec_reaper_add(struct reaper *reaper, reap_func_t f, void *data)
81{
82 struct reaper_elm *reaper_elm;
83 struct slist_elm *elm;
84 int ret = 0;
85
86 pthread_mutex_lock(&reaper->mutex);
87
88 for (elm = reaper->reap_list.next; elm; elm = elm->next) {
89 reaper_elm = container_of(elm, struct reaper_elm, slist);
90
91 if (reaper_elm->data == data)
92 goto out_unlock;
93 }
94
95 reaper_elm = lightrec_malloc(reaper->state, MEM_FOR_LIGHTREC,
96 sizeof(*reaper_elm));
97 if (!reaper_elm) {
98 pr_err("Cannot add reaper entry: Out of memory\n");
99 ret = -ENOMEM;
100 goto out_unlock;
101 }
102
103 reaper_elm->func = f;
104 reaper_elm->data = data;
105 slist_append(&reaper->reap_list, &reaper_elm->slist);
106
107out_unlock:
108 pthread_mutex_unlock(&reaper->mutex);
109 return ret;
110}
111
98fa08a5
PC
112static bool lightrec_reaper_can_reap(struct reaper *reaper)
113{
114 return !atomic_load_explicit(&reaper->sem, memory_order_relaxed);
115}
116
a59e5536 117void lightrec_reaper_reap(struct reaper *reaper)
118{
119 struct reaper_elm *reaper_elm;
120 struct slist_elm *elm;
121
122 pthread_mutex_lock(&reaper->mutex);
123
98fa08a5
PC
124 while (lightrec_reaper_can_reap(reaper) &&
125 !!(elm = slist_first(&reaper->reap_list))) {
a59e5536 126 slist_remove(&reaper->reap_list, elm);
ba3814c1 127 reaper->running = true;
a59e5536 128 pthread_mutex_unlock(&reaper->mutex);
129
130 reaper_elm = container_of(elm, struct reaper_elm, slist);
131
98fa08a5 132 (*reaper_elm->func)(reaper->state, reaper_elm->data);
a59e5536 133
134 lightrec_free(reaper->state, MEM_FOR_LIGHTREC,
135 sizeof(*reaper_elm), reaper_elm);
136
137 pthread_mutex_lock(&reaper->mutex);
ba3814c1
PC
138 reaper->running = false;
139 pthread_cond_broadcast(&reaper->cond);
a59e5536 140 }
141
142 pthread_mutex_unlock(&reaper->mutex);
143}
98fa08a5
PC
144
145void lightrec_reaper_pause(struct reaper *reaper)
146{
147 atomic_fetch_add_explicit(&reaper->sem, 1, memory_order_relaxed);
ba3814c1
PC
148
149 pthread_mutex_lock(&reaper->mutex);
150 while (reaper->running)
151 pthread_cond_wait(&reaper->cond, &reaper->mutex);
152 pthread_mutex_unlock(&reaper->mutex);
98fa08a5
PC
153}
154
155void lightrec_reaper_continue(struct reaper *reaper)
156{
157 atomic_fetch_sub_explicit(&reaper->sem, 1, memory_order_relaxed);
158}