* fix async texture cache not working on IOS due to sem_open requirement

* allow semaphore to be unlinked and close no thread exit
* removed firstTry as it can now use s_pSem which is only set when the semaphore is successfully created.  Had to move target->retain() under thread creation so we don't leak memory if semaphore fails.
This commit is contained in:
Jeff Reitman 2012-05-27 11:41:12 -07:00
parent b7746882f7
commit 6c6fbeef8d
1 changed files with 64 additions and 18 deletions

View File

@ -43,6 +43,7 @@ THE SOFTWARE.
#include "CCThread.h" #include "CCThread.h"
#include "semaphore.h" #include "semaphore.h"
#include "CCString.h" #include "CCString.h"
#include <errno.h>
using namespace std; using namespace std;
@ -67,7 +68,22 @@ static pthread_t s_loadingThread;
static pthread_mutex_t s_asyncStructQueueMutex; static pthread_mutex_t s_asyncStructQueueMutex;
static pthread_mutex_t s_ImageInfoMutex; static pthread_mutex_t s_ImageInfoMutex;
static sem_t s_sem; static sem_t* s_pSem = NULL;
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS
#define CC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE 1
#else
#define CC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE 0
#endif
#if CC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE
#define CC_ASYNC_TEXTURE_CACHE_SEMAPHORE "ccAsync"
#else
static sem_t s_sem;
#endif
static bool need_quit; static bool need_quit;
static std::queue<AsyncStruct*> *s_pAsyncStructQueue; static std::queue<AsyncStruct*> *s_pAsyncStructQueue;
@ -104,7 +120,12 @@ static void* loadImage(void* data)
while (true) while (true)
{ {
// wait for rendering thread to ask for loading if s_pAsyncStructQueue is empty // wait for rendering thread to ask for loading if s_pAsyncStructQueue is empty
sem_wait(&s_sem); int semWaitRet = sem_wait(s_pSem);
if( semWaitRet < 0 )
{
CCLOG( "CCTextureCache async thread semaphore error: %s\n", strerror( errno ) );
break;
}
std::queue<AsyncStruct*> *pQueue = s_pAsyncStructQueue; std::queue<AsyncStruct*> *pQueue = s_pAsyncStructQueue;
@ -112,10 +133,10 @@ static void* loadImage(void* data)
if (pQueue->empty()) if (pQueue->empty())
{ {
pthread_mutex_unlock(&s_asyncStructQueueMutex); pthread_mutex_unlock(&s_asyncStructQueueMutex);
if (need_quit) if (need_quit)
break; break;
else else
continue; continue;
} }
else else
{ {
@ -157,6 +178,17 @@ static void* loadImage(void* data)
pthread_mutex_unlock(&s_ImageInfoMutex); pthread_mutex_unlock(&s_ImageInfoMutex);
} }
if( s_pSem != NULL )
{
#if CC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE
sem_unlink(CC_ASYNC_TEXTURE_CACHE_SEMAPHORE);
sem_close(s_pSem);
#else
sem_destroy(s_pSem);
#endif
s_pSem = NULL;
}
return 0; return 0;
} }
@ -184,7 +216,7 @@ CCTextureCache::~CCTextureCache()
{ {
CCLOGINFO("cocos2d: deallocing CCTextureCache."); CCLOGINFO("cocos2d: deallocing CCTextureCache.");
need_quit = true; need_quit = true;
sem_post(&s_sem); sem_post(s_pSem);
CC_SAFE_RELEASE(m_pTextures); CC_SAFE_RELEASE(m_pTextures);
} }
@ -235,27 +267,41 @@ void CCTextureCache::addImageAsync(const char *path, CCObject *target, SEL_CallF
return; return;
} }
if (target)
{
target->retain();
}
// lazy init // lazy init
static bool firstRun = true; if (s_pSem == NULL)
if (firstRun)
{ {
#if CC_ASYNC_TEXTURE_CACHE_USE_NAMED_SEMAPHORE
s_pSem = sem_open(CC_ASYNC_TEXTURE_CACHE_SEMAPHORE, O_CREAT | O_EXCL, 0644, 0);
if( s_pSem == SEM_FAILED )
{
CCLOG( "CCTextureCache async thread semaphore init error: %s\n", strerror( errno ) );
s_pSem = NULL;
return;
}
#else
int semInitRet = sem_init(&s_sem, 0, 0);
if( semInitRet < 0 )
{
CCLOG( "CCTextureCache async thread semaphore init error: %s\n", strerror( errno ) );
return;
}
s_pSem = &s_sem;
#endif
s_pAsyncStructQueue = new queue<AsyncStruct*>(); s_pAsyncStructQueue = new queue<AsyncStruct*>();
s_pImageQueue = new queue<ImageInfo*>(); s_pImageQueue = new queue<ImageInfo*>();
pthread_mutex_init(&s_asyncStructQueueMutex, NULL); pthread_mutex_init(&s_asyncStructQueueMutex, NULL);
sem_init(&s_sem, 0, 0);
pthread_mutex_init(&s_ImageInfoMutex, NULL); pthread_mutex_init(&s_ImageInfoMutex, NULL);
pthread_create(&s_loadingThread, NULL, loadImage, NULL); pthread_create(&s_loadingThread, NULL, loadImage, NULL);
CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(CCTextureCache::addImageAsyncCallBack), this, 0, false); CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(CCTextureCache::addImageAsyncCallBack), this, 0, false);
need_quit = false; need_quit = false;
firstRun = false; }
if (target)
{
target->retain();
} }
// generate async struct // generate async struct
@ -269,7 +315,7 @@ void CCTextureCache::addImageAsync(const char *path, CCObject *target, SEL_CallF
s_pAsyncStructQueue->push(data); s_pAsyncStructQueue->push(data);
pthread_mutex_unlock(&s_asyncStructQueueMutex); pthread_mutex_unlock(&s_asyncStructQueueMutex);
sem_post(&s_sem); sem_post(s_pSem);
} }
void CCTextureCache::addImageAsyncCallBack(ccTime dt) void CCTextureCache::addImageAsyncCallBack(ccTime dt)