usbloadergx/source/libwiigui/gui_image_async.cpp

150 lines
3.7 KiB
C++
Raw Normal View History

2009-09-27 20:19:53 +02:00
/****************************************************************************
* USB Loader GX
2009-09-27 20:19:53 +02:00
*
* gui_imagea_sync.cpp
***************************************************************************/
#include <unistd.h>
#include "gui_image_async.h"
std::vector<GuiImageAsync *> GuiImageAsync::List;
lwp_t GuiImageAsync::Thread = LWP_THREAD_NULL;
mutex_t GuiImageAsync::ListLock = LWP_THREAD_NULL;
GuiImageAsync * GuiImageAsync::InUse = NULL;
u32 GuiImageAsync::ThreadCount = 0;
bool GuiImageAsync::ThreadSleep = true;
bool GuiImageAsync::CloseThread = false;
static inline void * memdup(const void* src, size_t len)
{
if(!src) return NULL;
void *dst = malloc(len);
if (dst) memcpy(dst, src, len);
return dst;
}
static GuiImageData * StdImageLoaderCallback(void *arg)
{
return new GuiImageData((char *) arg);
}
GuiImageAsync::GuiImageAsync(const char *Filename, GuiImageData * PreloadImg) :
GuiImage(PreloadImg), imgData(NULL), callback(StdImageLoaderCallback), arg(strdup(Filename))
{
ThreadInit();
ThreadAddImage(this);
}
GuiImageAsync::GuiImageAsync(ImageLoaderCallback Callback, const void * Arg, int ArgLen, GuiImageData * PreloadImg) :
GuiImage(PreloadImg), imgData(NULL), callback(Callback), arg(memdup(Arg, ArgLen))
{
ThreadInit();
ThreadAddImage(this);
}
GuiImageAsync::~GuiImageAsync()
{
ThreadRemoveImage(this);
ThreadExit();
while(InUse == this) usleep(100);
if (imgData) delete imgData;
if (arg) free(arg);
}
2009-09-27 20:19:53 +02:00
void GuiImageAsync::ThreadAddImage(GuiImageAsync *Image)
{
LWP_MutexLock(ListLock);
List.push_back(Image);
LWP_MutexUnlock(ListLock);
ThreadSleep = false;
LWP_ResumeThread(Thread);
}
void GuiImageAsync::ThreadRemoveImage(GuiImageAsync *Image)
{
for(u32 i = 0; i < List.size(); ++i)
{
if(List[i] == Image)
{
LWP_MutexLock(ListLock);
List.erase(List.begin()+i);
LWP_MutexUnlock(ListLock);
break;
}
}
2009-09-27 20:19:53 +02:00
}
void GuiImageAsync::ClearQueue()
{
LWP_MutexLock(ListLock);
List.clear();
LWP_MutexUnlock(ListLock);
2009-09-27 20:19:53 +02:00
}
void * GuiImageAsync::GuiImageAsyncThread(void *arg)
{
while(!CloseThread)
{
if(ThreadSleep)
LWP_SuspendThread(Thread);
2009-09-27 20:19:53 +02:00
while(!List.empty() && !CloseThread)
{
LWP_MutexLock(ListLock);
InUse = List.front();
2010-09-24 02:48:03 +02:00
List.erase(List.begin());
LWP_MutexUnlock(ListLock);
2009-09-27 20:19:53 +02:00
if (!InUse)
continue;
InUse->imgData = InUse->callback(InUse->arg);
if (InUse->imgData && InUse->imgData->GetImage())
{
InUse->width = InUse->imgData->GetWidth();
InUse->height = InUse->imgData->GetHeight();
InUse->image = InUse->imgData->GetImage();
}
InUse = NULL;
}
ThreadSleep = true;
}
return NULL;
2009-09-27 20:19:53 +02:00
}
u32 GuiImageAsync::ThreadInit()
{
if (Thread == LWP_THREAD_NULL)
{
2010-09-24 02:48:03 +02:00
LWP_MutexInit(&ListLock, false);
LWP_CreateThread(&Thread, GuiImageAsyncThread, NULL, NULL, 32768, 80);
}
return ++ThreadCount;
2009-09-27 20:19:53 +02:00
}
u32 GuiImageAsync::ThreadExit()
{
//! We don't need to always shutdown and startup the thread, especially
//! since this is a nested startup/shutdown from the gui thread.
//! It's fine with being put to suspended only.
/*
2010-09-24 02:48:03 +02:00
if (--ThreadCount == 0)
{
CloseThread = true;
2010-09-24 02:48:03 +02:00
LWP_ResumeThread(Thread);
LWP_JoinThread(Thread, NULL);
LWP_MutexUnlock(ListLock);
2010-09-24 02:48:03 +02:00
LWP_MutexDestroy(ListLock);
Thread = LWP_THREAD_NULL;
ListLock = LWP_MUTEX_NULL;
ListLock = LWP_MUTEX_NULL;
}
*/
return --ThreadCount;
2009-09-27 20:19:53 +02:00
}