+#if !USE_READ_THREAD
+static void readThreadStop() {}
+static void readThreadStart() {}
+#else
+static pthread_t read_thread_id;
+
+static pthread_cond_t read_thread_msg_avail;
+static pthread_cond_t read_thread_msg_done;
+static pthread_mutex_t read_thread_msg_lock;
+
+static pthread_cond_t sectorbuffer_cond;
+static pthread_mutex_t sectorbuffer_lock;
+
+static boolean read_thread_running = FALSE;
+static int read_thread_sector_start = -1;
+static int read_thread_sector_end = -1;
+
+typedef struct {
+ int sector;
+ long ret;
+ unsigned char data[CD_FRAMESIZE_RAW];
+} SectorBufferEntry;
+
+#define SECTOR_BUFFER_SIZE 4096
+
+static SectorBufferEntry *sectorbuffer;
+static size_t sectorbuffer_index;
+
+int (*sync_cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
+unsigned char *(*sync_CDR_getBuffer)(void);
+
+static unsigned char * CALLBACK ISOgetBuffer_async(void);
+static int cdread_async(FILE *f, unsigned int base, void *dest, int sector);
+
+static void *readThreadMain(void *param) {
+ int max_sector = -1;
+ int requested_sector_start = -1;
+ int requested_sector_end = -1;
+ int last_read_sector = -1;
+ int index = 0;
+
+ int ra_sector = -1;
+ int max_ra = 128;
+ int initial_ra = 1;
+ int speedmult_ra = 4;
+
+ int ra_count = 0;
+ int how_far_ahead = 0;
+
+ unsigned char tmpdata[CD_FRAMESIZE_RAW];
+ long ret;
+
+ max_sector = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length);
+
+ while(1) {
+ pthread_mutex_lock(&read_thread_msg_lock);
+
+ // If we don't have readahead and we don't have a sector request, wait for one.
+ // If we still have readahead to go, don't block, just keep going.
+ // And if we ever have a sector request pending, acknowledge and reset it.
+
+ if (!ra_count) {
+ if (read_thread_sector_start == -1 && read_thread_running) {
+ pthread_cond_wait(&read_thread_msg_avail, &read_thread_msg_lock);
+ }
+ }
+
+ if (read_thread_sector_start != -1) {
+ requested_sector_start = read_thread_sector_start;
+ requested_sector_end = read_thread_sector_end;
+ read_thread_sector_start = -1;
+ read_thread_sector_end = -1;
+ pthread_cond_signal(&read_thread_msg_done);
+ }
+
+ pthread_mutex_unlock(&read_thread_msg_lock);
+
+ if (!read_thread_running)
+ break;
+
+ // Readahead code, based on the implementation in mednafen psx's cdromif.cpp
+ if (requested_sector_start != -1) {
+ if (last_read_sector != -1 && last_read_sector == (requested_sector_start - 1)) {
+ how_far_ahead = ra_sector - requested_sector_end;
+
+ if(how_far_ahead <= max_ra)
+ ra_count = (max_ra - how_far_ahead + 1 ? max_ra - how_far_ahead + 1 : speedmult_ra);
+ else
+ ra_count++;
+ } else if (requested_sector_end != last_read_sector) {
+ ra_sector = requested_sector_end;
+ ra_count = initial_ra;
+ }
+
+ last_read_sector = requested_sector_end;
+ }
+
+ index = ra_sector % SECTOR_BUFFER_SIZE;
+
+ // check for end of CD
+ if (ra_count && ra_sector >= max_sector) {
+ ra_count = 0;
+ pthread_mutex_lock(§orbuffer_lock);
+ sectorbuffer[index].ret = -1;
+ sectorbuffer[index].sector = ra_sector;
+ pthread_cond_signal(§orbuffer_cond);
+ pthread_mutex_unlock(§orbuffer_lock);
+ }
+
+ if (ra_count) {
+ pthread_mutex_lock(§orbuffer_lock);
+ if (sectorbuffer[index].sector != ra_sector) {
+ pthread_mutex_unlock(§orbuffer_lock);
+
+ ret = sync_cdimg_read_func(cdHandle, 0, tmpdata, ra_sector);
+
+ pthread_mutex_lock(§orbuffer_lock);
+ sectorbuffer[index].ret = ret;
+ sectorbuffer[index].sector = ra_sector;
+ memcpy(sectorbuffer[index].data, tmpdata, CD_FRAMESIZE_RAW);
+ }
+ pthread_cond_signal(§orbuffer_cond);
+ pthread_mutex_unlock(§orbuffer_lock);
+
+ ra_sector++;
+ ra_count--;
+ }
+ }
+
+ return NULL;