X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flightrec%2Frecompiler.c;h=634d3d015bb7ff64fe241b10b93285a6646dddd4;hb=ea17432f22e441c9bf6f1c60f58a8cc6faaebbb1;hp=379881a08ac479884fa75a16071835162fee3538;hpb=d16005f843cd28ae90f091bd4e39a90b355e1d45;p=pcsx_rearmed.git diff --git a/deps/lightrec/recompiler.c b/deps/lightrec/recompiler.c index 379881a0..634d3d01 100644 --- a/deps/lightrec/recompiler.c +++ b/deps/lightrec/recompiler.c @@ -16,6 +16,7 @@ #include "interpreter.h" #include "lightrec-private.h" #include "memmanager.h" +#include "slist.h" #include #include @@ -25,7 +26,7 @@ struct block_rec { struct block *block; - struct block_rec *next; + struct slist_elm slist; }; struct recompiler { @@ -35,31 +36,19 @@ struct recompiler { pthread_mutex_t mutex; bool stop; struct block *current_block; - struct block_rec *list; + struct slist_elm slist; }; -static void slist_remove(struct recompiler *rec, struct block_rec *elm) -{ - struct block_rec *prev; - - if (rec->list == elm) { - rec->list = elm->next; - } else { - for (prev = rec->list; prev && prev->next != elm; ) - prev = prev->next; - if (prev) - prev->next = elm->next; - } -} - static void lightrec_compile_list(struct recompiler *rec) { - struct block_rec *next; + struct block_rec *block_rec; + struct slist_elm *next; struct block *block; int ret; - while (!!(next = rec->list)) { - block = next->block; + while (!!(next = slist_first(&rec->slist))) { + block_rec = container_of(next, struct block_rec, slist); + block = block_rec->block; rec->current_block = block; pthread_mutex_unlock(&rec->mutex); @@ -72,9 +61,9 @@ static void lightrec_compile_list(struct recompiler *rec) pthread_mutex_lock(&rec->mutex); - slist_remove(rec, next); + slist_remove(&rec->slist, next); lightrec_free(rec->state, MEM_FOR_LIGHTREC, - sizeof(*next), next); + sizeof(*block_rec), block_rec); pthread_cond_signal(&rec->cond); } @@ -87,19 +76,21 @@ static void * lightrec_recompiler_thd(void *d) pthread_mutex_lock(&rec->mutex); - for (;;) { + while (!rec->stop) { do { pthread_cond_wait(&rec->cond, &rec->mutex); - if (rec->stop) { - pthread_mutex_unlock(&rec->mutex); - return NULL; - } + if (rec->stop) + goto out_unlock; - } while (!rec->list); + } while (slist_empty(&rec->slist)); lightrec_compile_list(rec); } + +out_unlock: + pthread_mutex_unlock(&rec->mutex); + return NULL; } struct recompiler *lightrec_recompiler_init(struct lightrec_state *state) @@ -116,7 +107,7 @@ struct recompiler *lightrec_recompiler_init(struct lightrec_state *state) rec->state = state; rec->stop = false; rec->current_block = NULL; - rec->list = NULL; + slist_init(&rec->slist); ret = pthread_cond_init(&rec->cond, NULL); if (ret) { @@ -164,60 +155,77 @@ void lightrec_free_recompiler(struct recompiler *rec) int lightrec_recompiler_add(struct recompiler *rec, struct block *block) { - struct block_rec *block_rec, *prev; + struct slist_elm *elm, *prev; + struct block_rec *block_rec; + int ret = 0; pthread_mutex_lock(&rec->mutex); - for (block_rec = rec->list, prev = NULL; block_rec; - prev = block_rec, block_rec = block_rec->next) { + /* 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) + goto out_unlock; + + for (elm = slist_first(&rec->slist), prev = NULL; elm; + prev = elm, elm = elm->next) { + block_rec = container_of(elm, struct block_rec, slist); + if (block_rec->block == block) { /* The block to compile is already in the queue - bump - * it to the top of the list */ - if (prev) { - prev->next = block_rec->next; - block_rec->next = rec->list; - rec->list = block_rec; + * it to the top of the list, unless the block is being + * recompiled. */ + if (prev && !(block->flags & BLOCK_SHOULD_RECOMPILE)) { + slist_remove_next(prev); + slist_append(&rec->slist, elm); } - pthread_mutex_unlock(&rec->mutex); - return 0; + goto out_unlock; } } /* By the time this function was called, the block has been recompiled * and ins't in the wait list anymore. Just return here. */ - if (block->function) { - pthread_mutex_unlock(&rec->mutex); - return 0; - } + if (block->function && !(block->flags & BLOCK_SHOULD_RECOMPILE)) + goto out_unlock; block_rec = lightrec_malloc(rec->state, MEM_FOR_LIGHTREC, sizeof(*block_rec)); if (!block_rec) { - pthread_mutex_unlock(&rec->mutex); - return -ENOMEM; + ret = -ENOMEM; + goto out_unlock; } pr_debug("Adding block PC 0x%x to recompiler\n", block->pc); block_rec->block = block; - block_rec->next = rec->list; - rec->list = block_rec; + + elm = &rec->slist; + + /* If the block is being recompiled, push it to the end of the queue; + * otherwise push it to the front of the queue. */ + if (block->flags & BLOCK_SHOULD_RECOMPILE) + for (; elm->next; elm = elm->next); + + slist_append(elm, &block_rec->slist); /* Signal the thread */ pthread_cond_signal(&rec->cond); - pthread_mutex_unlock(&rec->mutex); - return 0; +out_unlock: + pthread_mutex_unlock(&rec->mutex); + return ret; } void lightrec_recompiler_remove(struct recompiler *rec, struct block *block) { struct block_rec *block_rec; + struct slist_elm *elm; pthread_mutex_lock(&rec->mutex); - for (block_rec = rec->list; block_rec; block_rec = block_rec->next) { + for (elm = slist_first(&rec->slist); elm; elm = elm->next) { + block_rec = container_of(elm, struct block_rec, slist); + if (block_rec->block == block) { if (block == rec->current_block) { /* Block is being recompiled - wait for @@ -229,7 +237,7 @@ void lightrec_recompiler_remove(struct recompiler *rec, struct block *block) } else { /* Block is not yet being processed - remove it * from the list */ - slist_remove(rec, block_rec); + slist_remove(&rec->slist, elm); lightrec_free(rec->state, MEM_FOR_LIGHTREC, sizeof(*block_rec), block_rec); }