1 |
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pspkerror.h>
#include "pte_osal.h"
#include "pthread.h"
#include "tls-helper.h"
#include <sys/time.h>
#include <sys/types.h>
#include <sys/timeb.h>
#define MAX_PSP_UID 2048
#define DEFAULT_STACK_SIZE_BYTES 4096
#define PSP_MAX_TLS 32
#if 1
#define PSP_DEBUG(x) printf(x)
#else
#define PSP_DEBUG(x)
#endif
static unsigned int threadDataKey;
typedef struct pspThreadData
{
pte_osThreadEntryPoint entryPoint;
void * argv;
SceUID cancelSem;
} pspThreadData;
static void *globalTls;
static pspThreadData *getThreadData(SceUID threadHandle);
static void *getTlsStructFromThread(SceUID thid);
int pspStubThreadEntry (unsigned int argc, void *argv)
{
int result;
pspThreadData *pThreadData;
pThreadData = getThreadData(sceKernelGetThreadId());
result = (*(pThreadData->entryPoint))(pThreadData->argv);
return result;
}
pte_osResult pte_osInit(void)
{
pte_osResult result;
pspThreadData *pThreadData;
char cancelSemName[64];
result = pteTlsGlobalInit(PSP_MAX_TLS);
if (result == PTE_OS_OK)
{
result = pteTlsAlloc(&threadDataKey);
if (result == PTE_OS_OK)
{
globalTls = pteTlsThreadInit();
pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
if (pThreadData == NULL)
{
result = PTE_OS_NO_RESOURCES;
}
else
{
pteTlsSetValue(globalTls, threadDataKey, pThreadData);
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSemGlobal");
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
0,
0,
255,
0);
result = PTE_OS_OK;
}
}
}
return result;
}
pte_osResult pte_osThreadCreate(pte_osThreadEntryPoint entryPoint,
int stackSize,
int initialPriority,
void *argv,
pte_osThreadHandle* ppte_osThreadHandle)
{
char threadName[64];
char cancelSemName[64];
static int threadNum = 1;
int pspAttr;
void *pTls;
SceUID threadId;
pte_osResult result;
pspThreadData *pThreadData;
if (threadNum++ > MAX_PSP_UID)
{
threadNum = 0;
}
if (stackSize < DEFAULT_STACK_SIZE_BYTES)
{
stackSize = DEFAULT_STACK_SIZE_BYTES;
}
pTls = pteTlsThreadInit();
if (pTls == NULL)
{
PSP_DEBUG("pteTlsThreadInit: PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
goto FAIL0;
}
pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
if (pThreadData == NULL)
{
pteTlsThreadDestroy(pTls);
PSP_DEBUG("malloc(pspThreadData): PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
goto FAIL0;
}
pteTlsSetValue(pTls, threadDataKey, pThreadData);
pThreadData->entryPoint = entryPoint;
pThreadData->argv = argv;
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSem%04d", threadNum);
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
0,
0,
255,
0);
snprintf(threadName, sizeof(threadName), "pthread%04d__%x", threadNum, (unsigned int) pTls);
pspAttr = 0;
threadId = sceKernelCreateThread(threadName,
pspStubThreadEntry,
initialPriority,
stackSize,
pspAttr,
NULL);
if (threadId == (SceUID) SCE_KERNEL_ERROR_NO_MEMORY)
{
free(pThreadData);
pteTlsThreadDestroy(pTls);
PSP_DEBUG("sceKernelCreateThread: PTE_OS_NO_RESOURCES\n");
result = PTE_OS_NO_RESOURCES;
}
else if (threadId < 0)
{
free(pThreadData);
pteTlsThreadDestroy(pTls);
PSP_DEBUG("sceKernelCreateThread: PTE_OS_GENERAL_FAILURE\n");
result = PTE_OS_GENERAL_FAILURE;
}
else
{
*ppte_osThreadHandle = threadId;
result = PTE_OS_OK;
}
FAIL0:
return result;
}
pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle)
{
sceKernelStartThread(osThreadHandle, 0, NULL);
return PTE_OS_OK;
}
pte_osResult pte_osThreadDelete(pte_osThreadHandle handle)
{
pspThreadData *pThreadData;
void *pTls;
pTls = getTlsStructFromThread(handle);
pThreadData = getThreadData(handle);
sceKernelDeleteSema(pThreadData->cancelSem);
free(pThreadData);
pteTlsThreadDestroy(pTls);
sceKernelDeleteThread(handle);
return PTE_OS_OK;
}
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle)
{
pte_osThreadDelete(handle);
sceKernelExitDeleteThread(0);
return PTE_OS_OK;
}
void pte_osThreadExit()
{
sceKernelExitThread(0);
}
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)
{
pte_osResult result;
pspThreadData *pThreadData;
pThreadData = getThreadData(sceKernelGetThreadId());
while (1)
{
SceKernelThreadRunStatus info;
memset(&info,0,sizeof(info));
info.size = sizeof(info);
sceKernelReferThreadRunStatus(threadHandle, &info);
if (info.status == PSP_THREAD_STOPPED)
{
result = PTE_OS_OK;
break;
}
else
{
SceKernelSemaInfo semInfo;
if (pThreadData != NULL)
{
SceUID osResult;
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
{
result = PTE_OS_INTERRUPTED;
break;
}
else
{
sceKernelDelayThread(POLLING_DELAY_IN_us);
}
}
else
{
result = PTE_OS_GENERAL_FAILURE;
break;
}
}
}
}
return result;
}
pte_osThreadHandle pte_osThreadGetHandle(void)
{
return sceKernelGetThreadId();
}
int pte_osThreadGetPriority(pte_osThreadHandle threadHandle)
{
SceKernelThreadInfo thinfo;
thinfo.size = sizeof(SceKernelThreadInfo);
sceKernelReferThreadStatus(threadHandle, &thinfo);
return thinfo.currentPriority;
}
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority)
{
sceKernelChangeThreadPriority(threadHandle, newPriority);
return PTE_OS_OK;
}
pte_osResult pte_osThreadCancel(pte_osThreadHandle threadHandle)
{
SceUID osResult;
pte_osResult result;
pspThreadData *pThreadData;
pThreadData = getThreadData(threadHandle);
osResult = sceKernelSignalSema(pThreadData->cancelSem, 1);
if (osResult == SCE_KERNEL_ERROR_OK)
{
result = PTE_OS_OK;
}
else
{
result = PTE_OS_GENERAL_FAILURE;
}
return result;
}
pte_osResult pte_osThreadCheckCancel(pte_osThreadHandle threadHandle)
{
pspThreadData *pThreadData;
SceKernelSemaInfo semInfo;
SceUID osResult;
pte_osResult result;
pThreadData = getThreadData(threadHandle);
if (pThreadData != NULL)
{
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
{
result = PTE_OS_INTERRUPTED;
}
else
{
result = PTE_OS_OK;
}
}
else
{
result = PTE_OS_GENERAL_FAILURE;
}
}
else
{
result = PTE_OS_GENERAL_FAILURE;
}
return result;
}
void pte_osThreadSleep(unsigned int msecs)
{
sceKernelDelayThread(msecs*1000);
}
int pte_osThreadGetMinPriority()
{
return 17;
}
int pte_osThreadGetMaxPriority()
{
return 30;
}
int pte_osThreadGetDefaultPriority()
{
return 18;
}
pte_osResult pte_osMutexCreate(pte_osMutexHandle *pHandle)
{
static int mutexCtr = 0;
char mutexName[32];
pte_osMutexHandle handle;
if (mutexCtr++ > MAX_PSP_UID)
{
mutexCtr = 0;
}
snprintf(mutexName,sizeof(mutexName),"mutex%d",mutexCtr);
handle = sceKernelCreateSema(mutexName,
0,
1,
1,
0);
*pHandle = handle;
return PTE_OS_OK;
}
pte_osResult pte_osMutexDelete(pte_osMutexHandle handle)
{
sceKernelDeleteSema(handle);
return PTE_OS_OK;
}
pte_osResult pte_osMutexLock(pte_osMutexHandle handle)
{
sceKernelWaitSema(handle, 1, NULL);
return PTE_OS_OK;
}
pte_osResult pte_osMutexTimedLock(pte_osMutexHandle handle, unsigned int timeoutMsecs)
{
pte_osResult result;
SceUInt timeoutUsecs = timeoutMsecs*1000;
int status = sceKernelWaitSema(handle, 1, &timeoutUsecs);
if (status < 0)
{
result = PTE_OS_TIMEOUT;
}
else
{
result = PTE_OS_OK;
}
return result;
}
pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle)
{
sceKernelSignalSema(handle, 1);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphoreCreate(int initialValue, pte_osSemaphoreHandle *pHandle)
{
pte_osSemaphoreHandle handle;
static int semCtr = 0;
char semName[32];
if (semCtr++ > MAX_PSP_UID)
{
semCtr = 0;
}
snprintf(semName,sizeof(semName),"pthread_sem%d",semCtr);
handle = sceKernelCreateSema(semName,
0,
initialValue,
SEM_VALUE_MAX,
0);
*pHandle = handle;
return PTE_OS_OK;
}
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)
{
sceKernelDeleteSema(handle);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count)
{
sceKernelSignalSema(handle, count);
return PTE_OS_OK;
}
pte_osResult pte_osSemaphorePend(pte_osSemaphoreHandle handle, unsigned int *pTimeoutMsecs)
{
unsigned int timeoutUsecs;
unsigned int *pTimeoutUsecs;
SceUInt result;
pte_osResult osResult;
if (pTimeoutMsecs == NULL)
{
pTimeoutUsecs = NULL;
}
else
{
timeoutUsecs = *pTimeoutMsecs * 1000;
pTimeoutUsecs = &timeoutUsecs;
}
result = sceKernelWaitSema(handle, 1, pTimeoutUsecs);
if (result == SCE_KERNEL_ERROR_OK)
{
osResult = PTE_OS_OK;
}
else if (result == SCE_KERNEL_ERROR_WAIT_TIMEOUT)
{
osResult = PTE_OS_TIMEOUT;
}
else
{
osResult = PTE_OS_GENERAL_FAILURE;
}
return osResult;
}
pte_osResult pte_osSemaphoreCancellablePend(pte_osSemaphoreHandle semHandle, unsigned int *pTimeout)
{
pspThreadData *pThreadData;
pThreadData = getThreadData(sceKernelGetThreadId());
clock_t start_time;
pte_osResult result = PTE_OS_OK;
unsigned int timeout;
unsigned char timeoutEnabled;
start_time = clock();
if (pTimeout == NULL)
{
timeout = 0;
timeoutEnabled = 0;
}
else
{
timeout = *pTimeout * 1000;
timeoutEnabled = 1;
}
while (1)
{
SceUInt semTimeout;
int status;
semTimeout = 0;
status = sceKernelWaitSema(semHandle, 1, &semTimeout);
if (status == SCE_KERNEL_ERROR_OK)
{
result = PTE_OS_OK;
break;
}
else if ((timeoutEnabled) && ((clock() - start_time) > timeout))
{
result = PTE_OS_TIMEOUT;
break;
}
else
{
SceKernelSemaInfo semInfo;
if (pThreadData != NULL)
{
SceUID osResult;
osResult = sceKernelReferSemaStatus(pThreadData->cancelSem, &semInfo);
if (osResult == SCE_KERNEL_ERROR_OK)
{
if (semInfo.currentCount > 0)
{
result = PTE_OS_INTERRUPTED;
break;
}
else
{
sceKernelDelayThread(POLLING_DELAY_IN_us);
}
}
else
{
result = PTE_OS_GENERAL_FAILURE;
break;
}
}
}
}
return result;
}
int pte_osAtomicExchange(int *ptarg, int val)
{
int intc = pspSdkDisableInterrupts();
int origVal;
origVal = *ptarg;
*ptarg = val;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicCompareExchange(int *pdest, int exchange, int comp)
{
int intc = pspSdkDisableInterrupts();
int origVal;
origVal = *pdest;
if (*pdest == comp)
{
*pdest = exchange;
}
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicExchangeAdd(int volatile* pAddend, int value)
{
int origVal;
int intc = pspSdkDisableInterrupts();
origVal = *pAddend;
*pAddend += value;
pspSdkEnableInterrupts(intc);
return origVal;
}
int pte_osAtomicDecrement(int *pdest)
{
int val;
int intc = pspSdkDisableInterrupts();
(*pdest)--;
val = *pdest;
pspSdkEnableInterrupts(intc);
return val;
}
int pte_osAtomicIncrement(int *pdest)
{
int val;
int intc = pspSdkDisableInterrupts();
(*pdest)++;
val = *pdest;
pspSdkEnableInterrupts(intc);
return val;
}
static pspThreadData *getThreadData(SceUID threadHandle)
{
pspThreadData *pThreadData;
void *pTls;
pTls = getTlsStructFromThread(threadHandle);
pThreadData = (pspThreadData *) pteTlsGetValue(pTls, threadDataKey);
return pThreadData;
}
static void *getTlsStructFromThread(SceUID thid)
{
SceKernelThreadInfo thinfo;
unsigned int ptr;
unsigned int thrNum;
void *pTls;
int numMatches;
thinfo.size = sizeof(SceKernelThreadInfo);
sceKernelReferThreadStatus(thid, &thinfo);
numMatches = sscanf(thinfo.name,"pthread%04d__%x", &thrNum, &ptr);
if (numMatches == 2)
{
pTls = (void *) ptr;
}
else
{
pTls = globalTls;
}
return pTls;
}
pte_osResult pte_osTlsSetValue(unsigned int key, void * value)
{
void *pTls;
pTls = getTlsStructFromThread(sceKernelGetThreadId());
return pteTlsSetValue(pTls, key, value);
}
void * pte_osTlsGetValue(unsigned int index)
{
void *pTls;
pTls = getTlsStructFromThread(sceKernelGetThreadId());
return (void *) pteTlsGetValue(pTls, index);
}
pte_osResult pte_osTlsAlloc(unsigned int *pKey)
{
void * pTls;
pTls = getTlsStructFromThread(sceKernelGetThreadId());
return pteTlsAlloc(pKey);
}
pte_osResult pte_osTlsFree(unsigned int index)
{
return pteTlsFree(index);
}
int ftime(struct timeb *tb)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
tb->time = tv.tv_sec;
tb->millitm = tv.tv_usec / 1000;
tb->timezone = tz.tz_minuteswest;
tb->dstflag = tz.tz_dsttime;
return 0;
}
|