summaryrefslogtreecommitdiffstats
path: root/src/core/CdStreamPosix.cpp
diff options
context:
space:
mode:
authormajestic <majesticcoding@gmail.com>2020-10-09 04:22:50 +0200
committermajestic <majesticcoding@gmail.com>2020-10-09 04:28:31 +0200
commitc091a5c11a826665f083ee7e73635f03aa4b550d (patch)
tree21f0d517e5210b1bc28d39ebfe67c2b0bcbb2772 /src/core/CdStreamPosix.cpp
parentMerge branch 'miami' of https://github.com/GTAmodding/re3 into miami (diff)
parentFix POSIX streaming (diff)
downloadre3-c091a5c11a826665f083ee7e73635f03aa4b550d.tar
re3-c091a5c11a826665f083ee7e73635f03aa4b550d.tar.gz
re3-c091a5c11a826665f083ee7e73635f03aa4b550d.tar.bz2
re3-c091a5c11a826665f083ee7e73635f03aa4b550d.tar.lz
re3-c091a5c11a826665f083ee7e73635f03aa4b550d.tar.xz
re3-c091a5c11a826665f083ee7e73635f03aa4b550d.tar.zst
re3-c091a5c11a826665f083ee7e73635f03aa4b550d.zip
Diffstat (limited to 'src/core/CdStreamPosix.cpp')
-rw-r--r--src/core/CdStreamPosix.cpp302
1 files changed, 162 insertions, 140 deletions
diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp
index e114a29a..a6ab62bc 100644
--- a/src/core/CdStreamPosix.cpp
+++ b/src/core/CdStreamPosix.cpp
@@ -34,11 +34,11 @@ struct CdReadInfo
bool bReading;
int32 nStatus;
#ifdef ONE_THREAD_PER_CHANNEL
- int8 nThreadStatus; // 0: created 1:initalized 2:abort now
- pthread_t pChannelThread;
- sem_t pStartSemaphore;
+ int8 nThreadStatus; // 0: created 1:priority set up 2:abort now
+ pthread_t pChannelThread;
+ sem_t *pStartSemaphore;
#endif
- sem_t pDoneSemaphore; // used for CdStreamSync
+ sem_t *pDoneSemaphore; // used for CdStreamSync
int32 hFile;
};
@@ -51,8 +51,8 @@ char *gImgNames[MAX_CDIMAGES];
#ifndef ONE_THREAD_PER_CHANNEL
pthread_t _gCdStreamThread;
-sem_t gCdStreamSema; // released when we have new thing to read(so channel is set)
-int8 gCdStreamThreadStatus; // 0: created 1:initalized 2:abort now
+sem_t *gCdStreamSema; // released when we have new thing to read(so channel is set)
+int8 gCdStreamThreadStatus; // 0: created 1:priority set up 2:abort now
Queue gChannelRequestQ;
bool _gbCdStreamOverlapped;
#endif
@@ -69,49 +69,50 @@ void
CdStreamInitThread(void)
{
int status;
-
+ char semName[20];
#ifndef ONE_THREAD_PER_CHANNEL
gChannelRequestQ.items = (int32 *)calloc(gNumChannels + 1, sizeof(int32));
gChannelRequestQ.head = 0;
gChannelRequestQ.tail = 0;
gChannelRequestQ.size = gNumChannels + 1;
ASSERT(gChannelRequestQ.items != nil );
- status = sem_init(&gCdStreamSema, 0, 0);
-#endif
+ gCdStreamSema = sem_open("/semaphore_cd_stream", O_CREAT, 0644, 1);
- if (status == -1) {
+ if (gCdStreamSema == SEM_FAILED) {
CDTRACE("failed to create stream semaphore");
ASSERT(0);
return;
}
-
+#endif
if ( gNumChannels > 0 )
{
for ( int32 i = 0; i < gNumChannels; i++ )
{
- status = sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0);
+ sprintf(semName,"/semaphore_done%d",i);
+ gpReadInfo[i].pDoneSemaphore = sem_open(semName, O_CREAT, 0644, 1);
- if (status == -1)
+ if (gpReadInfo[i].pDoneSemaphore == SEM_FAILED)
{
CDTRACE("failed to create sync semaphore");
ASSERT(0);
return;
}
#ifdef ONE_THREAD_PER_CHANNEL
- status = sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0);
+ sprintf(semName,"/semaphore_start%d",i);
+ gpReadInfo[i].pStartSemaphore = sem_open(semName, O_CREAT, 0644, 1);
- if (status == -1)
+ if (gpReadInfo[i].pStartSemaphore == SEM_FAILED)
{
CDTRACE("failed to create start semaphore");
ASSERT(0);
return;
}
- gpReadInfo[i].nThreadStatus = 0;
+ gpReadInfo[i].nThreadStatus = 0;
int *channelI = (int*)malloc(sizeof(int));
*channelI = i;
- status = pthread_create(&gpReadInfo[i].pChannelThread, NULL, CdStreamThread, (void*)channelI);
+ status = pthread_create(&gpReadInfo[i].pChannelThread, NULL, CdStreamThread, (void*)channelI);
if (status == -1)
{
@@ -124,32 +125,32 @@ CdStreamInitThread(void)
}
#ifndef ONE_THREAD_PER_CHANNEL
- debug("Using one streaming thread for all channels\n");
- status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil);
- gCdStreamThreadStatus = 0;
-
- if (status == -1)
- {
- CDTRACE("failed to create sync thread");
- ASSERT(0);
- return;
- }
+ debug("Using one streaming thread for all channels\n");
+ gCdStreamThreadStatus = 0;
+ status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil);
+
+ if (status == -1)
+ {
+ CDTRACE("failed to create sync thread");
+ ASSERT(0);
+ return;
+ }
#else
- debug("Using seperate streaming threads for each channel\n");
+ debug("Using separate streaming threads for each channel\n");
#endif
}
void
CdStreamInit(int32 numChannels)
{
- struct statvfs fsInfo;
-
- if((statvfs("models/gta3.img", &fsInfo)) < 0)
- {
- CDTRACE("can't get filesystem info");
- ASSERT(0);
- return;
- }
+ struct statvfs fsInfo;
+
+ if((statvfs("models/gta3.img", &fsInfo)) < 0)
+ {
+ CDTRACE("can't get filesystem info");
+ ASSERT(0);
+ return;
+ }
#ifdef __linux__
_gdwCdStreamFlags = O_RDONLY | O_NOATIME;
#else
@@ -163,7 +164,7 @@ CdStreamInit(int32 numChannels)
debug("Using no buffered loading for streaming\n");
}
*/
- void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, fsInfo.f_bsize);
+ void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, (RwUInt32)fsInfo.f_bsize);
ASSERT( pBuffer != nil );
gNumImages = 0;
@@ -185,27 +186,27 @@ uint32
GetGTA3ImgSize(void)
{
ASSERT( gImgFiles[0] > 0 );
- struct stat statbuf;
+ struct stat statbuf;
- char path[PATH_MAX];
- realpath(gImgNames[0], path);
- if (stat(path, &statbuf) == -1) {
+ char path[PATH_MAX];
+ realpath(gImgNames[0], path);
+ if (stat(path, &statbuf) == -1) {
// Try case-insensitivity
char* real = casepath(gImgNames[0], false);
if (real)
{
realpath(real, path);
free(real);
- if (stat(path, &statbuf) != -1)
+ if (stat(path, &statbuf) != -1)
goto ok;
}
- CDTRACE("can't get size of gta3.img");
- ASSERT(0);
- return 0;
- }
-ok:
- return statbuf.st_size;
+ CDTRACE("can't get size of gta3.img");
+ ASSERT(0);
+ return 0;
+ }
+ ok:
+ return (uint32)statbuf.st_size;
}
void
@@ -213,15 +214,13 @@ CdStreamShutdown(void)
{
// Destroying semaphores and free(gpReadInfo) will be done at threads
#ifndef ONE_THREAD_PER_CHANNEL
- gCdStreamThreadStatus = 2;
- sem_post(&gCdStreamSema);
-#endif
-
-#ifdef ONE_THREAD_PER_CHANNEL
- for ( int32 i = 0; i < gNumChannels; i++ ) {
- gpReadInfo[i].nThreadStatus = 2;
- sem_post(&gpReadInfo[i].pStartSemaphore);
- }
+ gCdStreamThreadStatus = 2;
+ sem_post(gCdStreamSema);
+#else
+ for ( int32 i = 0; i < gNumChannels; i++ ) {
+ gpReadInfo[i].nThreadStatus = 2;
+ sem_post(gpReadInfo[i].pStartSemaphore);
+ }
#endif
}
@@ -241,27 +240,33 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size)
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
- pChannel->hFile = hImage - 1;
- if ( pChannel->nSectorsToRead != 0 || pChannel->bReading )
- return STREAM_NONE;
+ if ( pChannel->nSectorsToRead != 0 || pChannel->bReading ) {
+ if (pChannel->nSectorOffset == _GET_OFFSET(offset) && pChannel->nSectorsToRead >= size)
+ return STREAM_SUCCESS;
+
+ flushStream[channel] = 1;
+ CdStreamSync(channel);
+ //return STREAM_NONE;
+ }
- pChannel->nStatus = STREAM_NONE;
- pChannel->nSectorOffset = _GET_OFFSET(offset);
- pChannel->nSectorsToRead = size;
- pChannel->pBuffer = buffer;
- pChannel->bLocked = 0;
+ pChannel->hFile = hImage - 1;
+ pChannel->nStatus = STREAM_NONE;
+ pChannel->nSectorOffset = _GET_OFFSET(offset);
+ pChannel->nSectorsToRead = size;
+ pChannel->pBuffer = buffer;
+ pChannel->bLocked = 0;
#ifndef ONE_THREAD_PER_CHANNEL
- AddToQueue(&gChannelRequestQ, channel);
- if ( sem_post(&gCdStreamSema) != 0 )
- printf("Signal Sema Error\n");
+ AddToQueue(&gChannelRequestQ, channel);
+ if ( sem_post(gCdStreamSema) != 0 )
+ printf("Signal Sema Error\n");
#else
- if ( sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 )
- printf("Signal Sema Error\n");
+ if ( sem_post(pChannel->pStartSemaphore) != 0 )
+ printf("Signal Sema Error\n");
#endif
- return STREAM_SUCCESS;
+ return STREAM_SUCCESS;
}
int32
@@ -272,29 +277,29 @@ CdStreamGetStatus(int32 channel)
ASSERT( pChannel != nil );
#ifdef ONE_THREAD_PER_CHANNEL
- if (pChannel->nThreadStatus == 2)
- return STREAM_NONE;
+ if (pChannel->nThreadStatus == 2)
+ return STREAM_NONE;
#else
- if (gCdStreamThreadStatus == 2)
- return STREAM_NONE;
+ if (gCdStreamThreadStatus == 2)
+ return STREAM_NONE;
#endif
- if ( pChannel->bReading )
- return STREAM_READING;
+ if ( pChannel->bReading )
+ return STREAM_READING;
- if ( pChannel->nSectorsToRead != 0 )
- return STREAM_WAITING;
+ if ( pChannel->nSectorsToRead != 0 )
+ return STREAM_WAITING;
- if ( pChannel->nStatus != STREAM_NONE )
- {
- int32 status = pChannel->nStatus;
+ if ( pChannel->nStatus != STREAM_NONE )
+ {
+ int32 status = pChannel->nStatus;
- pChannel->nStatus = STREAM_NONE;
+ pChannel->nStatus = STREAM_NONE;
- return status;
- }
+ return status;
+ }
- return STREAM_NONE;
+ return STREAM_NONE;
}
int32
@@ -314,30 +319,35 @@ CdStreamSync(int32 channel)
if (flushStream[channel]) {
#ifdef ONE_THREAD_PER_CHANNEL
pChannel->nSectorsToRead = 0;
- pthread_kill(gpReadInfo[channel].pChannelThread, SIGINT);
+ pthread_kill(pChannel->pChannelThread, SIGUSR1);
+ if (pChannel->bReading) {
+ pChannel->bLocked = true;
+ sem_wait(pChannel->pDoneSemaphore);
+ }
#else
+ pChannel->nSectorsToRead = 0;
if (pChannel->bReading) {
- pChannel->nSectorsToRead = 0;
- pthread_kill(_gCdStreamThread, SIGINT);
- } else {
- pChannel->nSectorsToRead = 0;
+ pChannel->bLocked = true;
+ pthread_kill(_gCdStreamThread, SIGUSR1);
+ sem_wait(pChannel->pDoneSemaphore);
+
}
#endif
pChannel->bReading = false;
flushStream[channel] = false;
- return STREAM_NONE;
+ return STREAM_NONE;
}
- if ( pChannel->nSectorsToRead != 0 )
- {
- pChannel->bLocked = true;
+ if ( pChannel->nSectorsToRead != 0 )
+ {
+ pChannel->bLocked = true;
- sem_wait(&pChannel->pDoneSemaphore);
- }
+ sem_wait(pChannel->pDoneSemaphore);
+ }
- pChannel->bReading = false;
+ pChannel->bReading = false;
- return pChannel->nStatus;
+ return pChannel->nStatus;
}
void
@@ -382,53 +392,52 @@ void *CdStreamThread(void *param)
debug("Created cdstream thread\n");
#ifndef ONE_THREAD_PER_CHANNEL
- while (gCdStreamThreadStatus != 2) {
- sem_wait(&gCdStreamSema);
- int32 channel = GetFirstInQueue(&gChannelRequestQ);
+ while (gCdStreamThreadStatus != 2) {
+ sem_wait(gCdStreamSema);
+ int32 channel = GetFirstInQueue(&gChannelRequestQ);
#else
- int channel = *((int*)param);
- while (gpReadInfo[channel].nThreadStatus != 2){
- sem_wait(&gpReadInfo[channel].pStartSemaphore);
+ int channel = *((int*)param);
+ while (gpReadInfo[channel].nThreadStatus != 2){
+ sem_wait(gpReadInfo[channel].pStartSemaphore);
#endif
- ASSERT( channel < gNumChannels );
CdReadInfo *pChannel = &gpReadInfo[channel];
ASSERT( pChannel != nil );
-#ifdef ONE_THREAD_PER_CHANNEL
- if (gpReadInfo[channel].nThreadStatus == 0){
- gpReadInfo[channel].nThreadStatus = 1;
-#else
- if (gCdStreamThreadStatus == 0){
- gCdStreamThreadStatus = 1;
-#endif
-
-#ifdef __linux__
- pid_t tid = syscall(SYS_gettid);
- int ret = setpriority(PRIO_PROCESS, tid, getpriority(PRIO_PROCESS, getpid()) + 1);
-#endif
- }
-
// spurious wakeup or we sent interrupt signal for flushing
if(pChannel->nSectorsToRead == 0)
- continue;
+ continue;
pChannel->bReading = true;
+ // Not standard POSIX :shrug:
+#ifdef __linux__
+#ifdef ONE_THREAD_PER_CHANNEL
+ if (gpReadInfo[channel].nThreadStatus == 0){
+ gpReadInfo[channel].nThreadStatus = 1;
+#else
+ if (gCdStreamThreadStatus == 0){
+ gCdStreamThreadStatus = 1;
+#endif
+ pid_t tid = syscall(SYS_gettid);
+ int ret = setpriority(PRIO_PROCESS, tid, getpriority(PRIO_PROCESS, getpid()) + 1);
+ }
+#endif
if ( pChannel->nStatus == STREAM_NONE )
{
- ASSERT(pChannel->hFile >= 0);
- ASSERT(pChannel->pBuffer != nil );
+ ASSERT(pChannel->hFile >= 0);
+ ASSERT(pChannel->pBuffer != nil );
lseek(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, SEEK_SET);
- if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) {
+ if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) {
// pChannel->nSectorsToRead == 0 at this point means we wanted to flush channel
- pChannel->nStatus = pChannel->nSectorsToRead == 0 ? STREAM_NONE : STREAM_ERROR;
- } else {
- pChannel->nStatus = STREAM_NONE;
- }
+ // STREAM_WAITING is a little hack to make CStreaming not process this data
+ pChannel->nStatus = pChannel->nSectorsToRead == 0 ? STREAM_WAITING : STREAM_ERROR;
+ } else {
+ pChannel->nStatus = STREAM_NONE;
+ }
}
-
+
#ifndef ONE_THREAD_PER_CHANNEL
RemoveFirstInQueue(&gChannelRequestQ);
#endif
@@ -437,22 +446,33 @@ void *CdStreamThread(void *param)
if ( pChannel->bLocked )
{
- sem_post(&pChannel->pDoneSemaphore);
+ sem_post(pChannel->pDoneSemaphore);
}
pChannel->bReading = false;
}
+ char semName[20];
#ifndef ONE_THREAD_PER_CHANNEL
- for ( int32 i = 0; i < gNumChannels; i++ )
- {
- sem_destroy(&gpReadInfo[i].pDoneSemaphore);
- }
- sem_destroy(&gCdStreamSema);
+ for ( int32 i = 0; i < gNumChannels; i++ )
+ {
+ sem_close(gpReadInfo[i].pDoneSemaphore);
+ sprintf(semName,"/semaphore_done%d",i);
+ sem_unlink(semName);
+ }
+ sem_close(gCdStreamSema);
+ sem_unlink("/semaphore_cd_stream");
free(gChannelRequestQ.items);
#else
- sem_destroy(&gpReadInfo[channel].pStartSemaphore);
- sem_destroy(&gpReadInfo[channel].pDoneSemaphore);
+ sem_close(gpReadInfo[channel].pStartSemaphore);
+ sprintf(semName,"/semaphore_start%d",channel);
+ sem_unlink(semName);
+
+ sem_close(gpReadInfo[channel].pDoneSemaphore);
+ sprintf(semName,"/semaphore_done%d",channel);
+ sem_unlink(semName);
#endif
- free(gpReadInfo);
+ if (gpReadInfo)
+ free(gpReadInfo);
+ gpReadInfo = nil;
pthread_exit(nil);
}
@@ -469,7 +489,7 @@ CdStreamAddImage(char const *path)
char* real = casepath(path, false);
if (real)
{
- gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);
+ gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);
free(real);
}
}
@@ -502,8 +522,10 @@ CdStreamGetImageName(int32 cd)
void
CdStreamRemoveImages(void)
{
- for ( int32 i = 0; i < gNumChannels; i++ )
+ for ( int32 i = 0; i < gNumChannels; i++ ) {
+ flushStream[i] = 1;
CdStreamSync(i);
+ }
for ( int32 i = 0; i < gNumImages; i++ )
{