diff --git a/app/src/main/cpp/archive.c b/app/src/main/cpp/archive.c index 1cec3d772..132b4bd45 100644 --- a/app/src/main/cpp/archive.c +++ b/app/src/main/cpp/archive.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -41,11 +42,13 @@ static JNIEnv *env; typedef struct { + int using; int next_index; struct archive *arc; struct archive_entry *entry; } archive_ctx; +pthread_mutex_t ctx_lock; static archive_ctx **ctx_pool; #define CTX_POOL_SIZE 20 @@ -103,6 +106,7 @@ static int archive_alloc_ctx(archive_ctx **ctxptr) { if (!ctx) return -ENOMEM; ctx->arc = archive_read_new(); + ctx->using = 1; if (!ctx->arc) { free(ctx); return -ENOMEM; @@ -137,9 +141,12 @@ static void archive_skip_to_index(archive_ctx *ctx, int index) { static int archive_get_ctx(archive_ctx **ctxptr, int idx) { archive_ctx *ctx = NULL; + pthread_mutex_lock(&ctx_lock); for (int i = 0; i < CTX_POOL_SIZE; i++) { if (!ctx_pool[i]) continue; + if (ctx_pool[i]->using) + continue; if (ctx_pool[i]->next_index > idx) continue; if (!ctx || ctx_pool[i]->next_index > ctx->next_index) @@ -147,27 +154,37 @@ static int archive_get_ctx(archive_ctx **ctxptr, int idx) { if (ctx->next_index == idx) break; } + if (ctx) + ctx->using = 1; + pthread_mutex_unlock(&ctx_lock); if (!ctx) { archive_ctx *victimCtx = NULL; int victimIdx = 0; + int replace = 1; int ret = archive_alloc_ctx(&ctx); if (ret) return ret; + pthread_mutex_lock(&ctx_lock); for (int i = 0; i < CTX_POOL_SIZE; i++) { if (!ctx_pool[i]) { ctx_pool[i] = ctx; - goto done; + replace = 0; + break; } + if (ctx_pool[i]->using) + continue; if (!victimCtx || ctx_pool[i]->next_index > victimCtx->next_index) { victimCtx = ctx_pool[i]; victimIdx = i; } } - archive_release_ctx(victimCtx); - ctx_pool[victimIdx] = ctx; + if (replace) { + archive_release_ctx(victimCtx); + ctx_pool[victimIdx] = ctx; + } + pthread_mutex_unlock(&ctx_lock); } - done: *ctxptr = ctx; archive_skip_to_index(ctx, idx); return 0; @@ -183,6 +200,7 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jint fd, } archiveSize = size; env = _; + pthread_mutex_init(&ctx_lock, 0); ctx_pool = calloc(CTX_POOL_SIZE, sizeof(archive_ctx **)); long r = archive_alloc_ctx(&ctx); if (r) { @@ -236,6 +254,7 @@ Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, memarea->size = (long) archive_entry_size(ctx->entry); memarea->buffer = malloc(memarea->size); ret = archive_read_data(ctx->arc, memarea->buffer, memarea->size); + ctx->using = 0; if (ret != memarea->size) LOGE("%s", "No enough data read, WTF?"); if (ret < 0) @@ -249,6 +268,7 @@ Java_com_hippo_UriArchiveAccessor_closeArchive(JNIEnv *jniEnv, jobject thiz) { archive_release_ctx(ctx_pool[i]); free(passwd); free(ctx_pool); + pthread_mutex_destroy(&ctx_lock); passwd = NULL; munmap(archiveAddr, archiveSize); } diff --git a/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java b/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java index e0e4785f5..1b37a8522 100644 --- a/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java +++ b/app/src/main/java/com/hippo/ehviewer/gallery/ArchiveGalleryProvider.java @@ -28,7 +28,6 @@ import com.hippo.UriArchiveAccessor; import com.hippo.ehviewer.GetText; import com.hippo.ehviewer.R; import com.hippo.ehviewer.Settings; -import com.hippo.glgallery.GalleryPageView; import com.hippo.image.Image; import com.hippo.unifile.UniFile; import com.hippo.yorozuya.thread.PVLock; @@ -48,11 +47,15 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { public static PVLock pv = new PVLock(0); private final UriArchiveAccessor archiveAccessor; private final Stack requests = new Stack<>(); - private final AtomicInteger extractingIndex = new AtomicInteger(GalleryPageView.INVALID_INDEX); private final LinkedHashMap streams = new LinkedHashMap<>(); - private final AtomicInteger decodingIndex = new AtomicInteger(GalleryPageView.INVALID_INDEX); private Thread archiveThread; - private Thread decodeThread; + private Thread[] decodeThread = new Thread[] { + new Thread(new DecodeTask()), + new Thread(new DecodeTask()), + new Thread(new DecodeTask()), + new Thread(new DecodeTask()) + }; + private volatile int size = STATE_WAIT; private String error; @@ -74,25 +77,22 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { int id = sIdGenerator.incrementAndGet(); archiveThread = new PriorityThread( - new ArchiveTask(), "ArchiveTask" + '-' + id, Process.THREAD_PRIORITY_BACKGROUND); + new ArchiveHostTask(), "ArchiveTask" + '-' + id, Process.THREAD_PRIORITY_BACKGROUND); archiveThread.start(); - - decodeThread = new PriorityThread( - new DecodeTask(), "DecodeTask" + '-' + id, Process.THREAD_PRIORITY_BACKGROUND); - decodeThread.start(); + for (Thread i : decodeThread) { + i.start(); + } } @Override public void stop() { super.stop(); - if (archiveThread != null) { archiveThread.interrupt(); archiveThread = null; } - if (decodeThread != null) { - decodeThread.interrupt(); - decodeThread = null; + for (Thread i : decodeThread) { + i.interrupt(); } try { archiveAccessor.close(); @@ -110,11 +110,11 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { protected void onRequest(int index) { boolean inDecodeTask; synchronized (streams) { - inDecodeTask = streams.containsKey(index) || index == decodingIndex.get(); + inDecodeTask = streams.containsKey(index); } synchronized (requests) { - boolean inArchiveTask = requests.contains(index) || index == extractingIndex.get(); + boolean inArchiveTask = requests.contains(index); if (!inArchiveTask && !inDecodeTask) { requests.add(index); requests.notify(); @@ -167,7 +167,14 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { return Integer.toString(index); } - private class ArchiveTask implements Runnable { + private class ArchiveHostTask implements Runnable { + public final Thread[] archiveThreads = new Thread[] { + new Thread(new ArchiveTask()), + new Thread(new ArchiveTask()), + new Thread(new ArchiveTask()), + new Thread(new ArchiveTask()) + }; + private void waitPasswd() throws InterruptedException { showPasswd.sendEmptyMessage(0); pv.p(); @@ -225,7 +232,26 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { } } } + for (Thread i : archiveThreads) { + i.start(); + } + Object o = new Object(); + synchronized (o) { + try { + o.wait(); + } catch (InterruptedException e) { + for (Thread i : archiveThreads) { + i.interrupt(); + } + } + } + } + } + + private class ArchiveTask implements Runnable { + @Override + public void run() { while (!Thread.currentThread().isInterrupted()) { int index; synchronized (requests) { @@ -239,12 +265,10 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { continue; } index = requests.pop(); - extractingIndex.lazySet(index); } // Check index valid if (index < 0 || index >= size) { - extractingIndex.lazySet(GalleryPageView.INVALID_INDEX); notifyPageFailed(index, GetText.getString(R.string.error_out_of_range)); continue; } @@ -276,7 +300,6 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { try { streams.wait(); } catch (InterruptedException e) { - // Interrupted break; } continue; @@ -287,18 +310,13 @@ public class ArchiveGalleryProvider extends GalleryProvider2 { iterator.remove(); index = entry.getKey(); addr = entry.getValue(); - decodingIndex.lazySet(index); } - try { - Image image = Image.decodeAddr(addr, true); - if (image != null) { - notifyPageSucceed(index, image); - } else { - notifyPageFailed(index, GetText.getString(R.string.error_decoding_failed)); - } - } finally { - decodingIndex.lazySet(GalleryPageView.INVALID_INDEX); + Image image = Image.decodeAddr(addr, true); + if (image != null) { + notifyPageSucceed(index, image); + } else { + notifyPageFailed(index, GetText.getString(R.string.error_decoding_failed)); } } }