X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flightrec%2Frecompiler.c;h=7350adba1d0586fefbec6158d94281d431a501f1;hb=0b8caa417c2bef660d6a0c70cbab71f1e997023b;hp=966635d4e7bfb5add5d294a2a8f75f4b5ac07639;hpb=25851a1e59d7c8607b4013dc3d3a092306b48389;p=pcsx_rearmed.git diff --git a/deps/lightrec/recompiler.c b/deps/lightrec/recompiler.c index 966635d4..7350adba 100644 --- a/deps/lightrec/recompiler.c +++ b/deps/lightrec/recompiler.c @@ -3,10 +3,12 @@ * Copyright (C) 2019-2021 Paul Cercueil */ +#include "blockcache.h" #include "debug.h" #include "interpreter.h" #include "lightrec-private.h" #include "memmanager.h" +#include "reaper.h" #include "slist.h" #include @@ -35,16 +37,18 @@ struct recompiler { pthread_cond_t cond; pthread_cond_t cond2; pthread_mutex_t mutex; - bool stop; + bool stop, must_flush; struct slist_elm slist; + pthread_mutex_t alloc_mutex; + unsigned int nb_recs; struct recompiler_thd thds[]; }; static unsigned int get_processors_count(void) { - unsigned int nb; + unsigned int nb = 1; #if defined(PTW32_VERSION) nb = pthread_num_processors_np(); @@ -53,7 +57,7 @@ static unsigned int get_processors_count(void) size_t size = sizeof(count); nb = sysctlbyname("hw.ncpu", &count, &size, NULL, 0) ? 1 : count; -#elif defined(__linux__) +#elif defined(_SC_NPROCESSORS_ONLN) nb = sysconf(_SC_NPROCESSORS_ONLN); #endif @@ -75,6 +79,58 @@ static struct slist_elm * lightrec_get_first_elm(struct slist_elm *head) return NULL; } +static bool lightrec_cancel_block_rec(struct recompiler *rec, + struct block_rec *block_rec) +{ + if (block_rec->compiling) { + /* Block is being recompiled - wait for + * completion */ + pthread_cond_wait(&rec->cond2, &rec->mutex); + + /* We can't guarantee the signal was for us. + * Since block_rec may have been removed while + * we were waiting on the condition, we cannot + * check block_rec->compiling again. The best + * thing is just to restart the function. */ + return false; + } + + /* Block is not yet being processed - remove it from the list */ + slist_remove(&rec->slist, &block_rec->slist); + lightrec_free(rec->state, MEM_FOR_LIGHTREC, + sizeof(*block_rec), block_rec); + + return true; +} + +static void lightrec_cancel_list(struct recompiler *rec) +{ + struct block_rec *block_rec; + struct slist_elm *next; + + while (!!(next = lightrec_get_first_elm(&rec->slist))) { + block_rec = container_of(next, struct block_rec, slist); + + lightrec_cancel_block_rec(rec, block_rec); + } + + pthread_cond_broadcast(&rec->cond2); +} + +static void lightrec_flush_code_buffer(struct lightrec_state *state, void *d) +{ + struct recompiler *rec = d; + + pthread_mutex_lock(&rec->mutex); + + if (rec->must_flush) { + lightrec_remove_outdated_blocks(state->block_cache, NULL); + rec->must_flush = false; + } + + pthread_mutex_unlock(&rec->mutex); +} + static void lightrec_compile_list(struct recompiler *rec, struct recompiler_thd *thd) { @@ -92,6 +148,21 @@ static void lightrec_compile_list(struct recompiler *rec, if (likely(!(block->flags & BLOCK_IS_DEAD))) { ret = lightrec_compile_block(thd->cstate, block); + if (ret == -ENOMEM) { + /* Code buffer is full. Request the reaper to + * flush it. */ + + pthread_mutex_lock(&rec->mutex); + if (!rec->must_flush) { + lightrec_reaper_add(rec->state->reaper, + lightrec_flush_code_buffer, + rec); + lightrec_cancel_list(rec); + rec->must_flush = true; + } + return; + } + if (ret) { pr_err("Unable to compile block at PC 0x%x: %d\n", block->pc, ret); @@ -162,6 +233,7 @@ struct recompiler *lightrec_recompiler_init(struct lightrec_state *state) rec->state = state; rec->stop = false; + rec->must_flush = false; rec->nb_recs = nb_recs; slist_init(&rec->slist); @@ -177,10 +249,16 @@ struct recompiler *lightrec_recompiler_init(struct lightrec_state *state) goto err_cnd_destroy; } + ret = pthread_mutex_init(&rec->alloc_mutex, NULL); + if (ret) { + pr_err("Cannot init alloc mutex variable: %d\n", ret); + goto err_cnd2_destroy; + } + ret = pthread_mutex_init(&rec->mutex, NULL); if (ret) { pr_err("Cannot init mutex variable: %d\n", ret); - goto err_cnd2_destroy; + goto err_alloc_mtx_destroy; } for (i = 0; i < nb_recs; i++) { @@ -199,6 +277,8 @@ struct recompiler *lightrec_recompiler_init(struct lightrec_state *state) err_mtx_destroy: pthread_mutex_destroy(&rec->mutex); +err_alloc_mtx_destroy: + pthread_mutex_destroy(&rec->alloc_mutex); err_cnd2_destroy: pthread_cond_destroy(&rec->cond2); err_cnd_destroy: @@ -221,6 +301,7 @@ void lightrec_free_recompiler(struct recompiler *rec) /* Stop the thread */ pthread_mutex_lock(&rec->mutex); pthread_cond_broadcast(&rec->cond); + lightrec_cancel_list(rec); pthread_mutex_unlock(&rec->mutex); for (i = 0; i < rec->nb_recs; i++) @@ -230,6 +311,7 @@ void lightrec_free_recompiler(struct recompiler *rec) lightrec_free_cstate(rec->thds[i].cstate); pthread_mutex_destroy(&rec->mutex); + pthread_mutex_destroy(&rec->alloc_mutex); pthread_cond_destroy(&rec->cond); pthread_cond_destroy(&rec->cond2); lightrec_free(rec->state, MEM_FOR_LIGHTREC, sizeof(*rec), rec); @@ -243,6 +325,12 @@ int lightrec_recompiler_add(struct recompiler *rec, struct block *block) pthread_mutex_lock(&rec->mutex); + /* If the recompiler must flush the code cache, we can't add the new + * job. It will be re-added next time the block's address is jumped to + * again. */ + if (rec->must_flush) + goto out_unlock; + /* If the block is marked as dead, don't compile it, it will be removed * as soon as it's safe. */ if (block->flags & BLOCK_IS_DEAD) @@ -312,28 +400,11 @@ void lightrec_recompiler_remove(struct recompiler *rec, struct block *block) for (elm = slist_first(&rec->slist); elm; elm = elm->next) { block_rec = container_of(elm, struct block_rec, slist); - if (block_rec->block != block) - continue; - - if (block_rec->compiling) { - /* Block is being recompiled - wait for - * completion */ - pthread_cond_wait(&rec->cond2, &rec->mutex); + if (block_rec->block == block) { + if (lightrec_cancel_block_rec(rec, block_rec)) + goto out_unlock; - /* We can't guarantee the signal was for us. - * Since block_rec may have been removed while - * we were waiting on the condition, we cannot - * check block_rec->compiling again. The best - * thing is just to restart the function. */ break; - } else { - /* Block is not yet being processed - remove it - * from the list */ - slist_remove(&rec->slist, elm); - lightrec_free(rec->state, MEM_FOR_LIGHTREC, - sizeof(*block_rec), block_rec); - - goto out_unlock; } } @@ -402,3 +473,13 @@ void * lightrec_recompiler_run_first_pass(struct lightrec_state *state, return NULL; } + +void lightrec_code_alloc_lock(struct lightrec_state *state) +{ + pthread_mutex_lock(&state->rec->alloc_mutex); +} + +void lightrec_code_alloc_unlock(struct lightrec_state *state) +{ + pthread_mutex_unlock(&state->rec->alloc_mutex); +}