mirror of
https://github.com/pspdev/pspsdk.git
synced 2025-10-03 16:51:27 +00:00
Merge pull request #90 from fjtrujy/master
Adding support for `std:thread`
This commit is contained in:
@@ -13,9 +13,10 @@ RUN cd /src && \
|
||||
make -j $(getconf _NPROCESSORS_ONLN) && \
|
||||
make -j $(getconf _NPROCESSORS_ONLN) install
|
||||
|
||||
## gcc needs to include libcglue libpsputility libpsprtc libpspnet_inet libpspnet_resolver libpspmodinfo libpspuser libpspkernel
|
||||
## gcc needs to include libcglue libpthreadglue libpsputility libpsprtc libpspnet_inet libpspnet_resolver libpspmodinfo libpspuser libpspkernel
|
||||
## from pspsdk to be able to build executables, because they are part of the standard libraries
|
||||
RUN ln -sf "$PSPDEV/psp/sdk/lib/libcglue.a" "$PSPDEV/psp/lib/libcglue.a" || { exit 1; }
|
||||
RUN ln -sf "$PSPDEV/psp/sdk/lib/libpthreadglue.a" "$PSPDEV/psp/lib/libpthreadglue.a" || { exit 1; }
|
||||
RUN ln -sf "$PSPDEV/psp/sdk/lib/libpsputility.a" "$PSPDEV/psp/lib/libpsputility.a" || { exit 1; }
|
||||
RUN ln -sf "$PSPDEV/psp/sdk/lib/libpsprtc.a" "$PSPDEV/psp/lib/libpsprtc.a" || { exit 1; }
|
||||
RUN ln -sf "$PSPDEV/psp/sdk/lib/libpspnet_inet.a" "$PSPDEV/psp/lib/libpspnet_inet.a" || { exit 1; }
|
||||
|
@@ -99,6 +99,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/hprm/Makefile
|
||||
src/kernel/Makefile
|
||||
src/libcglue/Makefile
|
||||
src/libpthreadglue/Makefile
|
||||
src/modinfo/Makefile
|
||||
src/mp3/Makefile
|
||||
src/mpeg/Makefile
|
||||
|
@@ -13,6 +13,7 @@ SUBDIRS = \
|
||||
hprm \
|
||||
kernel \
|
||||
libcglue \
|
||||
libpthreadglue \
|
||||
modinfo \
|
||||
mp3 \
|
||||
mpeg \
|
||||
|
@@ -65,7 +65,7 @@ LDFLAGS += -Wl,-zmax-page-size=128
|
||||
ifeq ($(USE_KERNEL_LIBS),1)
|
||||
LIBS := -nostdlib $(LIBS) -lpspdebug -lpspdisplay_driver -lpspctrl_driver -lpspmodinfo -lpspsdk -lpspkernel
|
||||
else
|
||||
LIBS := $(LIBS) -lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk \
|
||||
LIBS := $(LIBS) -lpspdebug -lpspdisplay -lpspge -lpspctrl \
|
||||
-lpspnet -lpspnet_apctl
|
||||
endif
|
||||
|
||||
|
@@ -33,7 +33,7 @@ LDFLAGS := $(addprefix -L,$(LIBDIR)) -Wl,-q,-T$(PSPSDK)/lib/linkfile.prx -nosta
|
||||
ifeq ($(USE_KERNEL_LIBS),1)
|
||||
LIBS := -nostdlib $(LIBS) -lpspdebug -lpspdisplay_driver -lpspctrl_driver -lpspmodinfo -lpspsdk -lpspkernel
|
||||
else
|
||||
LIBS := $(LIBS) -lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk
|
||||
LIBS := $(LIBS) -lpspdebug -lpspdisplay -lpspge -lpspctrl
|
||||
endif
|
||||
|
||||
ifeq ($(PSP_FW_VERSION),)
|
||||
|
@@ -31,7 +31,7 @@ GLUE_OBJS = __dummy_passwd.o __fill_stat.o __psp_heap_blockid.o __psp_free_heap.
|
||||
fsync.o getpwnam.o getuid.o geteuid.o
|
||||
|
||||
|
||||
INIT_OBJS = __libcglue_init.o __libcglue_deinit.o _exit.o abort.o exit.o
|
||||
INIT_OBJS = __libpthreadglue_init.o __libcglue_init.o __libcglue_deinit.o _exit.o abort.o exit.o
|
||||
|
||||
MUTEXMAN_OBJS = __malloc_mutex.o __sbrk_mutex.o __fdman_mutex.o __init_mutex.o __deinit_mutex.o
|
||||
|
||||
|
@@ -23,11 +23,25 @@ void __init_cwd(char *argv_0);
|
||||
void __timezone_update();
|
||||
void __fdman_init();
|
||||
void __init_mutex();
|
||||
void pthread_init();
|
||||
void __psp_free_heap();
|
||||
void __deinit_mutex();
|
||||
|
||||
extern int sce_newlib_nocreate_thread_in_start __attribute__((weak));
|
||||
|
||||
#ifdef F___libpthreadglue_init
|
||||
/* Note: This function is being called from __libcglue_init.
|
||||
* It is a weak function because can be override by user program
|
||||
*/
|
||||
__attribute__((weak))
|
||||
void __libpthreadglue_init()
|
||||
{
|
||||
pthread_init();
|
||||
}
|
||||
#else
|
||||
void __libpthreadglue_init();
|
||||
#endif
|
||||
|
||||
#ifdef F___libcglue_init
|
||||
/* Note: This function is being called from crt0.c/crt0_prx.c.
|
||||
* It is a weak function because can be override by user program,
|
||||
@@ -45,6 +59,9 @@ void __libcglue_init(int argc, char *argv[])
|
||||
/* Initialize filedescriptor management */
|
||||
__fdman_init();
|
||||
|
||||
/* Initialize pthread library */
|
||||
__libpthreadglue_init();
|
||||
|
||||
/* Initialize cwd from this program's path */
|
||||
__init_cwd(argv[0]);
|
||||
|
||||
|
@@ -19,6 +19,9 @@
|
||||
/* Fuctions from errno.c */
|
||||
int __set_errno(int code);
|
||||
|
||||
/* Fuctions from errno.c */
|
||||
int __set_errno(int code);
|
||||
|
||||
#ifdef F_nanosleep
|
||||
/* note: we don't use rem as we have no signals */
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem)
|
||||
|
42
src/libpthreadglue/Makefile.am
Normal file
42
src/libpthreadglue/Makefile.am
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
libdir = @PSPSDK_LIBDIR@
|
||||
|
||||
CC = @PSP_CC@
|
||||
CCAS = $(CC)
|
||||
AR = @PSP_AR@
|
||||
RANLIB = @PSP_RANLIB@
|
||||
|
||||
CPPFLAGS = -I$(top_srcdir)/src/base \
|
||||
-I$(top_srcdir)/src/debug \
|
||||
-I$(top_srcdir)/src/kernel \
|
||||
-I$(top_srcdir)/src/sdk \
|
||||
-I$(top_srcdir)/src/user
|
||||
|
||||
CFLAGS = @PSPSDK_CFLAGS@
|
||||
CCASFLAGS = $(CFLAGS)
|
||||
|
||||
OSAL_OBJS = __threadDataKey.o __getThreadData.o __pspStubThreadEntry.o \
|
||||
pte_osInit.o pte_osTerminate.o pte_osThreadCreate.o pte_osThreadStart.o pte_osThreadDelete.o \
|
||||
pte_osThreadExitAndDelete.o pte_osThreadExit.o pte_osThreadWaitForEnd.o pte_osThreadGetHandle.o pte_osThreadGetPriority.o pthread_num_processors_np.o \
|
||||
pte_osThreadSetPriority.o pte_osThreadCancel.o pte_osThreadCheckCancel.o pte_osThreadSleep.o pte_osThreadGetMinPriority.o pte_osThreadGetMaxPriority.o \
|
||||
pte_osThreadGetDefaultPriority.o pte_osMutexCreate.o pte_osMutexDelete.o pte_osMutexLock.o pte_osMutexTimedLock.o pte_osMutexUnlock.o \
|
||||
pte_osSemaphoreCreate.o pte_osSemaphoreDelete.o pte_osSemaphorePost.o pte_osSemaphorePend.o pte_osSemaphoreCancellablePend.o \
|
||||
pte_osAtomicExchange.o pte_osAtomicCompareExchange.o pte_osAtomicExchangeAdd.o pte_osAtomicDecrement.o pte_osAtomicIncrement.o
|
||||
|
||||
TLS_HELPER_OBJS = __keysUsed.o __maxTlsValues.o __globalTlsLock.o __globalTls.o pteTlsGlobalInit.o pteTlsThreadInit.o \
|
||||
__pteTlsAlloc.o pteTlsGetValue.o __pteTlsSetValue.o __getTlsStructFromThread.o getTlsStructFromThread.o pteTlsFree.o \
|
||||
pteTlsThreadDestroy.o pteTlsGlobalDestroy.o pte_osTlsSetValue.o pte_osTlsGetValue.o pte_osTlsAlloc.o pte_osTlsFree.o
|
||||
|
||||
lib_LIBRARIES = libpthreadglue.a
|
||||
|
||||
libpthreadglue_a_SOURCES = \
|
||||
osal.c \
|
||||
tls-helper.c
|
||||
|
||||
libpthreadglue_a_LIBADD = $(OSAL_OBJS) $(TLS_HELPER_OBJS)
|
||||
|
||||
$(OSAL_OBJS): osal.c
|
||||
$(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@
|
||||
|
||||
$(TLS_HELPER_OBJS): tls-helper.c
|
||||
$(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@
|
788
src/libpthreadglue/osal.c
Normal file
788
src/libpthreadglue/osal.c
Normal file
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
* PSP Software Development Kit - https://github.com/pspdev
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* osal.c - Pthread compatible system calls.
|
||||
*
|
||||
* Copyright (c) 2021 Francisco J Trujillo <fjtrujy@gmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pspkerror.h>
|
||||
#include <pspthreadman.h>
|
||||
#include <pspsdk.h>
|
||||
|
||||
|
||||
typedef int pte_osThreadHandle;
|
||||
typedef int pte_osSemaphoreHandle;
|
||||
typedef int pte_osMutexHandle;
|
||||
#include <sys/pte_generic_osal.h>
|
||||
|
||||
#define MAX_PSP_UID 2048 // SWAG
|
||||
#define DEFAULT_STACK_SIZE_BYTES 4096
|
||||
#define PSP_MAX_TLS 32
|
||||
|
||||
pte_osResult pteTlsGlobalInit(int maxEntries);
|
||||
void * pteTlsThreadInit(void);
|
||||
|
||||
pte_osResult __pteTlsAlloc(unsigned int *pKey);
|
||||
void * pteTlsGetValue(void *pTlsThreadStruct, unsigned int index);
|
||||
pte_osResult __pteTlsSetValue(void *pTlsThreadStruct, unsigned int index, void * value);
|
||||
void *__getTlsStructFromThread(SceUID thid);
|
||||
pte_osResult pteTlsFree(unsigned int index);
|
||||
|
||||
void pteTlsThreadDestroy(void * pTlsThreadStruct);
|
||||
void pteTlsGlobalDestroy(void);
|
||||
|
||||
#if 0
|
||||
#define PSP_DEBUG(x) printf(x)
|
||||
#else
|
||||
#define PSP_DEBUG(x)
|
||||
#endif
|
||||
|
||||
#define POLLING_DELAY_IN_us 100
|
||||
|
||||
/* TLS key used to access pspThreadData struct for reach thread. */
|
||||
#ifdef F___threadDataKey
|
||||
unsigned int __threadDataKey;
|
||||
#else
|
||||
extern unsigned int __threadDataKey;
|
||||
#endif
|
||||
|
||||
extern void *__globalTls;
|
||||
|
||||
/*
|
||||
* Data stored on a per-thread basis - allocated in pte_osThreadCreate
|
||||
* and freed in pte_osThreadDelete.
|
||||
*/
|
||||
typedef struct pspThreadData
|
||||
{
|
||||
/* Entry point and parameters to thread's main function */
|
||||
pte_osThreadEntryPoint entryPoint;
|
||||
void * argv;
|
||||
|
||||
/* Semaphore used for cancellation. Posted to by pte_osThreadCancel,
|
||||
polled in pte_osSemaphoreCancellablePend */
|
||||
SceUID cancelSem;
|
||||
|
||||
} pspThreadData;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Helper functions
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifdef F___getThreadData
|
||||
pspThreadData *__getThreadData(SceUID threadHandle)
|
||||
{
|
||||
pspThreadData *pThreadData;
|
||||
void *pTls;
|
||||
|
||||
pTls = __getTlsStructFromThread(threadHandle);
|
||||
pThreadData = (pspThreadData *) pteTlsGetValue(pTls, __threadDataKey);
|
||||
|
||||
return pThreadData;
|
||||
}
|
||||
#else
|
||||
pspThreadData *__getThreadData(SceUID threadHandle);
|
||||
#endif
|
||||
|
||||
/* A new thread's stub entry point. It retrieves the real entry point from the per thread control
|
||||
* data as well as any parameters to this function, and then calls the entry point.
|
||||
*/
|
||||
#ifdef F___pspStubThreadEntry
|
||||
int __pspStubThreadEntry(unsigned int argc, void *argv)
|
||||
{
|
||||
int result;
|
||||
pspThreadData *pThreadData;
|
||||
|
||||
pThreadData = __getThreadData(sceKernelGetThreadId());
|
||||
result = (*(pThreadData->entryPoint))(pThreadData->argv);
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
extern int __pspStubThreadEntry(unsigned int argc, void *argv);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Initialization
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifdef F_pte_osInit
|
||||
pte_osResult pte_osInit(void)
|
||||
{
|
||||
pte_osResult result;
|
||||
pspThreadData *pThreadData;
|
||||
char cancelSemName[64];
|
||||
|
||||
/* Allocate and initialize TLS support */
|
||||
result = pteTlsGlobalInit(PSP_MAX_TLS);
|
||||
|
||||
if (result == PTE_OS_OK) {
|
||||
/* Allocate a key that we use to store control information (e.g. cancellation semaphore) per thread */
|
||||
result = __pteTlsAlloc(&__threadDataKey);
|
||||
|
||||
if (result == PTE_OS_OK) {
|
||||
/* Initialize the structure used to emulate TLS for
|
||||
* non-POSIX threads
|
||||
*/
|
||||
__globalTls = pteTlsThreadInit();
|
||||
|
||||
/* Also create a "thread data" structure for a single non-POSIX thread. */
|
||||
|
||||
/* Allocate some memory for our per-thread control data. We use this for:
|
||||
* 1. Entry point and parameters for the user thread's main function.
|
||||
* 2. Semaphore used for thread cancellation.
|
||||
*/
|
||||
pThreadData = (pspThreadData *) malloc(sizeof(pspThreadData));
|
||||
|
||||
if (pThreadData == NULL) {
|
||||
result = PTE_OS_NO_RESOURCES;
|
||||
} else {
|
||||
/* Save a pointer to our per-thread control data as a TLS value */
|
||||
__pteTlsSetValue(__globalTls, __threadDataKey, pThreadData);
|
||||
|
||||
/* Create a semaphore used to cancel threads */
|
||||
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSemGlobal");
|
||||
|
||||
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
|
||||
0, /* attributes (default) */
|
||||
0, /* initial value */
|
||||
255, /* maximum value */
|
||||
0); /* options (default) */
|
||||
result = PTE_OS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osTerminate
|
||||
pte_osResult pte_osTerminate(void) {
|
||||
pteTlsGlobalDestroy();
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Threads
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifdef F_pte_osThreadCreate
|
||||
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;
|
||||
}
|
||||
|
||||
/* Make sure that the stack we're going to allocate is big enough */
|
||||
if (stackSize < DEFAULT_STACK_SIZE_BYTES) {
|
||||
stackSize = DEFAULT_STACK_SIZE_BYTES;
|
||||
}
|
||||
|
||||
/* Allocate TLS structure for this thread. */
|
||||
pTls = pteTlsThreadInit();
|
||||
if (pTls == NULL) {
|
||||
PSP_DEBUG("pteTlsThreadInit: PTE_OS_NO_RESOURCES\n");
|
||||
result = PTE_OS_NO_RESOURCES;
|
||||
goto FAIL0;
|
||||
}
|
||||
|
||||
/* Allocate some memory for our per-thread control data. We use this for:
|
||||
* 1. Entry point and parameters for the user thread's main function.
|
||||
* 2. Semaphore used for thread cancellation.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* Save a pointer to our per-thread control data as a TLS value */
|
||||
__pteTlsSetValue(pTls, __threadDataKey, pThreadData);
|
||||
|
||||
pThreadData->entryPoint = entryPoint;
|
||||
pThreadData->argv = argv;
|
||||
|
||||
/* Create a semaphore used to cancel threads */
|
||||
snprintf(cancelSemName, sizeof(cancelSemName), "pthread_cancelSem%04d", threadNum);
|
||||
|
||||
pThreadData->cancelSem = sceKernelCreateSema(cancelSemName,
|
||||
0, /* attributes (default) */
|
||||
0, /* initial value */
|
||||
255, /* maximum value */
|
||||
0); /* options (default) */
|
||||
|
||||
|
||||
/* In order to emulate TLS functionality, we append the address of the TLS structure that we
|
||||
* allocated above to the thread's name. To set or get TLS values for this thread, the user
|
||||
* needs to get the name of the thread from the OS and then parse the name to extract
|
||||
* a pointer to the TLS structure.
|
||||
*/
|
||||
snprintf(threadName, sizeof(threadName), "pthread%04d__%x", threadNum, (unsigned int) pTls);
|
||||
|
||||
pspAttr = 0;
|
||||
|
||||
// printf("%s %p %d %d %d\n",threadName, __pspStubThreadEntry, initialPriority, stackSize, pspAttr);
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadStart
|
||||
pte_osResult pte_osThreadStart(pte_osThreadHandle osThreadHandle)
|
||||
{
|
||||
sceKernelStartThread(osThreadHandle, 0, 0);
|
||||
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadDelete
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadExitAndDelete
|
||||
pte_osResult pte_osThreadExitAndDelete(pte_osThreadHandle handle)
|
||||
{
|
||||
pte_osThreadDelete(handle);
|
||||
sceKernelExitDeleteThread(0);
|
||||
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadExit
|
||||
void pte_osThreadExit()
|
||||
{
|
||||
sceKernelExitThread(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This has to be cancellable, so we can't just call sceKernelWaitThreadEnd.
|
||||
* Instead, poll on this in a loop, like we do for a cancellable semaphore.
|
||||
*/
|
||||
#ifdef F_pte_osThreadWaitForEnd
|
||||
pte_osResult pte_osThreadWaitForEnd(pte_osThreadHandle threadHandle)
|
||||
{
|
||||
pte_osResult result;
|
||||
pspThreadData *pThreadData;
|
||||
|
||||
pThreadData = __getThreadData(sceKernelGetThreadId());
|
||||
|
||||
while (1) {
|
||||
SceKernelThreadRunStatus info;
|
||||
|
||||
/* Poll task to see if it has ended */
|
||||
memset(&info,0,sizeof(info));
|
||||
info.size = sizeof(info);
|
||||
sceKernelReferThreadRunStatus(threadHandle, &info);
|
||||
|
||||
if (info.status == PSP_THREAD_STOPPED) {
|
||||
/* Thread has ended */
|
||||
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 {
|
||||
/* Nothing found and not timed out yet; let's yield so we're not
|
||||
* in busy loop.
|
||||
*/
|
||||
sceKernelDelayThread(POLLING_DELAY_IN_us);
|
||||
}
|
||||
} else {
|
||||
result = PTE_OS_GENERAL_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadGetHandle
|
||||
pte_osThreadHandle pte_osThreadGetHandle(void)
|
||||
{
|
||||
return sceKernelGetThreadId();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadGetPriority
|
||||
int pte_osThreadGetPriority(pte_osThreadHandle threadHandle)
|
||||
{
|
||||
SceKernelThreadInfo thinfo;
|
||||
|
||||
thinfo.size = sizeof(SceKernelThreadInfo);
|
||||
sceKernelReferThreadStatus(threadHandle, &thinfo);
|
||||
|
||||
return thinfo.currentPriority;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadSetPriority
|
||||
pte_osResult pte_osThreadSetPriority(pte_osThreadHandle threadHandle, int newPriority)
|
||||
{
|
||||
sceKernelChangeThreadPriority(threadHandle, newPriority);
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadCancel
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadCheckCancel
|
||||
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 {
|
||||
/* sceKernelReferSemaStatus returned an error */
|
||||
result = PTE_OS_GENERAL_FAILURE;
|
||||
}
|
||||
} else {
|
||||
/* For some reason, we couldn't get thread data */
|
||||
result = PTE_OS_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadSleep
|
||||
void pte_osThreadSleep(unsigned int msecs)
|
||||
{
|
||||
sceKernelDelayThread(msecs*1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadGetMinPriority
|
||||
int pte_osThreadGetMinPriority()
|
||||
{
|
||||
return 17;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadGetMaxPriority
|
||||
int pte_osThreadGetMaxPriority()
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osThreadGetDefaultPriority
|
||||
int pte_osThreadGetDefaultPriority()
|
||||
{
|
||||
return 18;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pthread_num_processors_np
|
||||
int pthread_num_processors_np(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Mutexes
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifdef F_pte_osMutexCreate
|
||||
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, /* attributes (default) */
|
||||
1, /* initial value */
|
||||
1, /* maximum value */
|
||||
0); /* options (default) */
|
||||
|
||||
*pHandle = handle;
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osMutexDelete
|
||||
pte_osResult pte_osMutexDelete(pte_osMutexHandle handle)
|
||||
{
|
||||
sceKernelDeleteSema(handle);
|
||||
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osMutexLock
|
||||
pte_osResult pte_osMutexLock(pte_osMutexHandle handle)
|
||||
{
|
||||
sceKernelWaitSema(handle, 1, NULL);
|
||||
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osMutexTimedLock
|
||||
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) {
|
||||
// Assume that any error from sceKernelWaitSema was due to a timeout
|
||||
result = PTE_OS_TIMEOUT;
|
||||
} else {
|
||||
result = PTE_OS_OK;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osMutexUnlock
|
||||
pte_osResult pte_osMutexUnlock(pte_osMutexHandle handle)
|
||||
{
|
||||
sceKernelSignalSema(handle, 1);
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Semaphores
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifdef F_pte_osSemaphoreCreate
|
||||
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, /* attributes (default) */
|
||||
initialValue, /* initial value */
|
||||
SEM_VALUE_MAX, /* maximum value */
|
||||
0); /* options (default) */
|
||||
|
||||
*pHandle = handle;
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osSemaphoreDelete
|
||||
pte_osResult pte_osSemaphoreDelete(pte_osSemaphoreHandle handle)
|
||||
{
|
||||
sceKernelDeleteSema(handle);
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osSemaphorePost
|
||||
pte_osResult pte_osSemaphorePost(pte_osSemaphoreHandle handle, int count)
|
||||
{
|
||||
sceKernelSignalSema(handle, count);
|
||||
return PTE_OS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osSemaphorePend
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Pend on a semaphore- and allow the pend to be cancelled.
|
||||
*
|
||||
* PSP OS provides no functionality to asynchronously interrupt a blocked call. We simulte
|
||||
* this by polling on the main semaphore and the cancellation semaphore and sleeping in a loop.
|
||||
*/
|
||||
#ifdef F_pte_osSemaphoreCancellablePend
|
||||
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();
|
||||
|
||||
// clock() is in microseconds, timeout as passed in was in milliseconds
|
||||
if (pTimeout == NULL) {
|
||||
timeout = 0;
|
||||
timeoutEnabled = 0;
|
||||
} else {
|
||||
timeout = *pTimeout * 1000;
|
||||
timeoutEnabled = 1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
SceUInt semTimeout;
|
||||
int status;
|
||||
|
||||
/* Poll semaphore */
|
||||
semTimeout = 0;
|
||||
status = sceKernelWaitSema(semHandle, 1, &semTimeout);
|
||||
|
||||
if (status == SCE_KERNEL_ERROR_OK) {
|
||||
/* User semaphore posted to */
|
||||
result = PTE_OS_OK;
|
||||
break;
|
||||
} else if ((timeoutEnabled) && ((clock() - start_time) > timeout)) {
|
||||
/* Timeout expired */
|
||||
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 {
|
||||
/* Nothing found and not timed out yet; let's yield so we're not
|
||||
* in busy loop.
|
||||
*/
|
||||
sceKernelDelayThread(POLLING_DELAY_IN_us);
|
||||
}
|
||||
} else {
|
||||
result = PTE_OS_GENERAL_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Atomic Operations
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifdef F_pte_osAtomicExchange
|
||||
int pte_osAtomicExchange(int *ptarg, int val)
|
||||
{
|
||||
int intc = pspSdkDisableInterrupts();
|
||||
int origVal;
|
||||
|
||||
origVal = *ptarg;
|
||||
*ptarg = val;
|
||||
|
||||
pspSdkEnableInterrupts(intc);
|
||||
return origVal;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osAtomicCompareExchange
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osAtomicExchangeAdd
|
||||
int pte_osAtomicExchangeAdd(int volatile* pAddend, int value)
|
||||
{
|
||||
int origVal;
|
||||
int intc = pspSdkDisableInterrupts();
|
||||
|
||||
origVal = *pAddend;
|
||||
*pAddend += value;
|
||||
|
||||
pspSdkEnableInterrupts(intc);
|
||||
return origVal;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osAtomicDecrement
|
||||
int pte_osAtomicDecrement(int *pdest)
|
||||
{
|
||||
int val;
|
||||
int intc = pspSdkDisableInterrupts();
|
||||
|
||||
(*pdest)--;
|
||||
val = *pdest;
|
||||
|
||||
pspSdkEnableInterrupts(intc);
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osAtomicIncrement
|
||||
int pte_osAtomicIncrement(int *pdest)
|
||||
{
|
||||
int val;
|
||||
int intc = pspSdkDisableInterrupts();
|
||||
|
||||
(*pdest)++;
|
||||
val = *pdest;
|
||||
|
||||
pspSdkEnableInterrupts(intc);
|
||||
return val;
|
||||
}
|
||||
#endif
|
254
src/libpthreadglue/tls-helper.c
Normal file
254
src/libpthreadglue/tls-helper.c
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* PSP Software Development Kit - https://github.com/pspdev
|
||||
* -----------------------------------------------------------------------
|
||||
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
||||
*
|
||||
* tls-helper.c - Pthread compatible system calls.
|
||||
*
|
||||
* Copyright (c) 2021 Francisco J Trujillo <fjtrujy@gmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pspkerneltypes.h>
|
||||
#include <pspthreadman.h>
|
||||
|
||||
typedef int pte_osThreadHandle;
|
||||
typedef int pte_osSemaphoreHandle;
|
||||
typedef int pte_osMutexHandle;
|
||||
#include <sys/pte_generic_osal.h>
|
||||
|
||||
#ifdef F___keysUsed
|
||||
int *__keysUsed;
|
||||
#else
|
||||
extern int *__keysUsed;
|
||||
#endif
|
||||
|
||||
#ifdef F___maxTlsValues
|
||||
int __maxTlsValues;
|
||||
#else
|
||||
extern int __maxTlsValues;
|
||||
#endif
|
||||
|
||||
#ifdef F___globalTlsLock
|
||||
pte_osMutexHandle __globalTlsLock;
|
||||
#else
|
||||
extern pte_osMutexHandle __globalTlsLock;
|
||||
#endif
|
||||
|
||||
/* Structure used to emulate TLS on non-POSIX threads.
|
||||
* This limits us to one non-POSIX thread that can
|
||||
* call pthread functions. */
|
||||
#ifdef F___globalTls
|
||||
void *__globalTls;
|
||||
#else
|
||||
extern void *__globalTls;
|
||||
#endif
|
||||
|
||||
#ifdef F_pteTlsGlobalInit
|
||||
pte_osResult pteTlsGlobalInit(int maxEntries)
|
||||
{
|
||||
int i;
|
||||
pte_osResult result;
|
||||
|
||||
pte_osMutexCreate(&__globalTlsLock);
|
||||
__keysUsed = (int *)malloc(maxEntries * sizeof(int));
|
||||
|
||||
if (__keysUsed != NULL) {
|
||||
for (i = 0; i < maxEntries; i++) {
|
||||
__keysUsed[i] = 0;
|
||||
}
|
||||
|
||||
__maxTlsValues = maxEntries;
|
||||
result = PTE_OS_OK;
|
||||
} else {
|
||||
result = PTE_OS_NO_RESOURCES;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pteTlsThreadInit
|
||||
void *pteTlsThreadInit(void)
|
||||
{
|
||||
void **pTlsStruct;
|
||||
int i;
|
||||
|
||||
pTlsStruct = (void **)malloc(__maxTlsValues * sizeof(void *));
|
||||
|
||||
// PTE library assumes that keys are initialized to zero
|
||||
for (i = 0; i < __maxTlsValues; i++) {
|
||||
pTlsStruct[i] = 0;
|
||||
}
|
||||
|
||||
return (void *)pTlsStruct;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F___pteTlsAlloc
|
||||
pte_osResult __pteTlsAlloc(unsigned int *pKey)
|
||||
{
|
||||
int i;
|
||||
pte_osResult result = PTE_OS_NO_RESOURCES;
|
||||
|
||||
pte_osMutexLock(__globalTlsLock);
|
||||
|
||||
for (i = 0; i < __maxTlsValues; i++) {
|
||||
if (__keysUsed[i] == 0) {
|
||||
__keysUsed[i] = 1;
|
||||
|
||||
*pKey = i + 1;
|
||||
result = PTE_OS_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pte_osMutexUnlock(__globalTlsLock);
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
pte_osResult __pteTlsAlloc(unsigned int *pKey);
|
||||
#endif
|
||||
|
||||
#ifdef F_pteTlsGetValue
|
||||
void *pteTlsGetValue(void *pTlsThreadStruct, unsigned int index)
|
||||
{
|
||||
void **pTls = (void **)pTlsThreadStruct;
|
||||
|
||||
if (__keysUsed[index - 1] && pTls != NULL) {
|
||||
return pTls[index - 1];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void *pteTlsGetValue(void *pTlsThreadStruct, unsigned int index);
|
||||
#endif
|
||||
|
||||
#ifdef F___pteTlsSetValue
|
||||
pte_osResult __pteTlsSetValue(void *pTlsThreadStruct, unsigned int index, void *value)
|
||||
{
|
||||
pte_osResult result;
|
||||
void **pTls = (void **)pTlsThreadStruct;
|
||||
|
||||
if (pTls != NULL) {
|
||||
pTls[index - 1] = value;
|
||||
result = PTE_OS_OK;
|
||||
} else {
|
||||
result = PTE_OS_INVALID_PARAM;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
pte_osResult __pteTlsSetValue(void *pTlsThreadStruct, unsigned int index, void *value);
|
||||
#endif
|
||||
|
||||
#ifdef F___getTlsStructFromThread
|
||||
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 we were called from a pthread, use the TLS allocated when the thread
|
||||
* was created. Otherwise, we were called from a non-pthread, so use the
|
||||
* "global". This is a pretty bad hack, but necessary due to lack of TLS on PSP.
|
||||
*/
|
||||
if (numMatches == 2) {
|
||||
pTls = (void *) ptr;
|
||||
} else {
|
||||
pTls = __globalTls;
|
||||
}
|
||||
|
||||
return pTls;
|
||||
}
|
||||
#else
|
||||
void *__getTlsStructFromThread(SceUID thid);
|
||||
#endif
|
||||
|
||||
#ifdef F_pteTlsFree
|
||||
pte_osResult pteTlsFree(unsigned int index)
|
||||
{
|
||||
pte_osResult result;
|
||||
|
||||
if (__keysUsed != NULL) {
|
||||
pte_osMutexLock(__globalTlsLock);
|
||||
__keysUsed[index - 1] = 0;
|
||||
pte_osMutexUnlock(__globalTlsLock);
|
||||
|
||||
result = PTE_OS_OK;
|
||||
} else {
|
||||
result = PTE_OS_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
pte_osResult pteTlsFree(unsigned int index);
|
||||
#endif
|
||||
|
||||
#ifdef F_pteTlsThreadDestroy
|
||||
void pteTlsThreadDestroy(void *pTlsThreadStruct)
|
||||
{
|
||||
free(pTlsThreadStruct);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pteTlsGlobalDestroy
|
||||
void pteTlsGlobalDestroy(void)
|
||||
{
|
||||
pte_osMutexDelete(__globalTlsLock);
|
||||
free(__keysUsed);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osTlsSetValue
|
||||
pte_osResult pte_osTlsSetValue(unsigned int key, void * value)
|
||||
{
|
||||
void *pTls;
|
||||
|
||||
pTls = __getTlsStructFromThread(sceKernelGetThreadId());
|
||||
|
||||
return __pteTlsSetValue(pTls, key, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osTlsGetValue
|
||||
void * pte_osTlsGetValue(unsigned int index)
|
||||
{
|
||||
void *pTls;
|
||||
|
||||
pTls = __getTlsStructFromThread(sceKernelGetThreadId());
|
||||
|
||||
return (void *) pteTlsGetValue(pTls, index);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osTlsAlloc
|
||||
pte_osResult pte_osTlsAlloc(unsigned int *pKey)
|
||||
{
|
||||
__getTlsStructFromThread(sceKernelGetThreadId());
|
||||
|
||||
return __pteTlsAlloc(pKey);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef F_pte_osTlsFree
|
||||
pte_osResult pte_osTlsFree(unsigned int index)
|
||||
{
|
||||
return pteTlsFree(index);
|
||||
}
|
||||
#endif
|
@@ -107,4 +107,8 @@ enum PspModuleInfoAttr
|
||||
void __libcglue_init(int argc, char *argv[]) {} \
|
||||
void __libcglue_deinit() {}
|
||||
|
||||
/* Disable the auto start of pthread on init for reducing binary size if not used. */
|
||||
#define PSP_DISABLE_AUTOSTART_PTHREAD() \
|
||||
void __libpthreadglue_init() {}
|
||||
|
||||
#endif /* PSPMODULEINFO_H */
|
||||
|
Reference in New Issue
Block a user