|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
The DRC no longer works at all on Linux, the 3dfx is completely busted, and I get a deadlock on exit. Not bad for a small patch ;-) Vas, if you see this and you're bored, get http://rbelmont.mameworld.info/sdlsync.c and fix my attempts at assembly InterlockedCompareExchange() implementations (modeled after the ones in Wine), that would probably help a lot :-)
Last edited by R. Belmont; 10/05/07 06:23 PM.
|
|
|
|
Joined: Feb 2007
Posts: 507
Senior Member
|
Senior Member
Joined: Feb 2007
Posts: 507 |
The DRC no longer works at all on Linux, the 3dfx is completely busted, and I get a deadlock on exit. Not bad for a small patch ;-) Vas, if you see this and you're bored, get http://rbelmont.mameworld.info/sdlsync.c and fix my attempts at assembly InterlockedCompareExchange() implementations (modeled after the ones in Wine), that would probably help a lot :-) Why are you not using the routines from sdlwork.c, i.e. INLINE void * compare_exchange_pointer(void * volatile *ptr, void *exchange, void *compare)
{
register void *ret;
__asm__ __volatile__ (
" lock ; cmpxchg %[exchange], %[ptr] ;"
: [ptr] "+m" (*ptr)
, [ret] "=a" (ret)
: [compare] "1" (compare)
, [exchange] "q" (exchange)
: "%cc"
);
return ret;
}
Or am I missing something?
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
You're missing that I didn't write sdlwork so I have no idea what's in it. Looks like those will do fine though, thanks for the pointer.
|
|
|
|
Joined: Feb 2004
Posts: 2,608 Likes: 315
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,608 Likes: 315 |
Yeah, I wrote most of the SDL-specific parts of current sdlwork.c (after copying the rest from the Windows version). If you want some help with any really low-level stuff, just yell. I like having an excuse to do some assembly language work.
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
It turns out we need interlocked compare exchange on INT32s, not the _pointer version. And sdlwork itself needs to change a lot for u3 - the Windows version has several new semantics and features. This is going to be fun. I've put what I have at: http://rbelmont.mameworld.info/sdlmame0119u3_pre1.zip[WARNING: DO NOT DOWNLOAD THAT VERSION IF YOU ONLY WANT TO PLAY GAMES!] It needs sdlwork upgraded to match the new Windows version, and then we can debug from there.
Last edited by R. Belmont; 10/06/07 04:32 AM.
|
|
|
|
Joined: Feb 2007
Posts: 507
Senior Member
|
Senior Member
Joined: Feb 2007
Posts: 507 |
I am a bit in a hurry so here is just some old code which may help: A while ago I proposed a common work.c implementation with abstraction on the sdlsync.c level. The following code contains implementations for windows-like events and thread allocation. The code is extracted from a diff and needs adaption. This would most probably go to sdlsync.c #ifndef SDLMAME_WIN32
#include <pthread.h>
#include <errno.h>
#include <sys/time.h>
-typedef struct _hidden_mutex_t hidden_mutex_t;
-struct _hidden_mutex_t {
#ifdef SDLMAME_MACOSX
#include <mach/mach.h>
#endif
struct _osd_lock {
pthread_mutex_t id;
};
struct _osd_event {
pthread_mutex_t mutex;
pthread_cond_t cond;
int autoreset;
volatile int signalled;
};
struct _osd_thread {
pthread_t thread;
};
static osd_lock *atomic_lck = NULL;
//============================================================
// osd_lock_alloc
//============================================================
osd_lock *osd_lock_alloc(void)
{
- hidden_mutex_t *mutex;
osd_lock *mutex;
pthread_mutexattr_t mtxattr;
- mutex = (hidden_mutex_t *)calloc(1, sizeof(hidden_mutex_t));
mutex = (osd_lock *)calloc(1, sizeof(osd_lock));
pthread_mutexattr_init(&mtxattr);
pthread_mutexattr_settype(&mtxattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex->id, &mtxattr);
- return (osd_lock *)mutex;
return mutex;
}
//============================================================
@@ -60,10 +77,9 @@
void osd_lock_acquire(osd_lock *lock)
{
- hidden_mutex_t *mutex = (hidden_mutex_t *) lock;
int r;
- r = pthread_mutex_lock(&mutex->id);
r = pthread_mutex_lock(&lock->id);
if (r==0)
return;
fprintf(stderr, "Error on lock: %d\n", r);
@@ -75,10 +91,9 @@
int osd_lock_try(osd_lock *lock)
{
- hidden_mutex_t *mutex = (hidden_mutex_t *) lock;
int r;
- r = pthread_mutex_trylock(&mutex->id);
r = pthread_mutex_trylock(&lock->id);
if (r==0)
return 1;
if (r!=EBUSY)
@@ -92,9 +107,7 @@
void osd_lock_release(osd_lock *lock)
{
- hidden_mutex_t *mutex = (hidden_mutex_t *) lock;
-
- pthread_mutex_unlock(&mutex->id);
pthread_mutex_unlock(&lock->id);
}
//============================================================
@@ -103,11 +116,195 @@
void osd_lock_free(osd_lock *lock)
{
- hidden_mutex_t *mutex = (hidden_mutex_t *) lock;
pthread_mutex_destroy(&lock->id);
free(lock);
}
//============================================================
// osd_num_processors
//============================================================
int osd_num_processors(void)
{
int processors = 1;
#ifdef SDLMAME_MACOSX
{
struct host_basic_info host_basic_info;
unsigned int count;
kern_return_t r;
mach_port_t my_mach_host_self;
count = HOST_BASIC_INFO_COUNT;
my_mach_host_self = mach_host_self();
if ( ( r = host_info(my_mach_host_self, HOST_BASIC_INFO, (host_info_t)(&host_basic_info), &count)) == KERN_SUCCESS )
{
processors = host_basic_info.avail_cpus;
}
mach_port_deallocate(mach_task_self(), my_mach_host_self);
}
#elif defined(_SC_NPROCESSORS_ONLN)
processors = sysconf(_SC_NPROCESSORS_ONLN);
#endif
return processors;
}
//============================================================
// osd_event_alloc
//============================================================
osd_event *osd_event_alloc(int manualreset, int initialstate)
{
osd_event *ev;
pthread_mutexattr_t mtxattr;
ev = (osd_event *)calloc(1, sizeof(osd_event));
pthread_mutexattr_init(&mtxattr);
pthread_mutex_init(&ev->mutex, &mtxattr);
pthread_cond_init(&ev->cond, NULL);
ev->signalled = initialstate;
ev->autoreset = !manualreset;
return ev;
}
//============================================================
// osd_event_free
//============================================================
void osd_event_free(osd_event *event)
{
pthread_mutex_destroy(&event->mutex);
pthread_cond_destroy(&event->cond);
free(event);
}
//============================================================
// osd_event_set
//============================================================
void osd_event_set(osd_event *event)
{
pthread_mutex_lock(&event->mutex);
event->signalled = TRUE;
pthread_cond_broadcast(&event->cond);
pthread_mutex_unlock(&event->mutex);
}
//============================================================
// osd_event_reset
//============================================================
void osd_event_reset(osd_event *event)
{
pthread_mutex_lock(&event->mutex);
event->signalled = FALSE;
pthread_mutex_unlock(&event->mutex);
}
//============================================================
// osd_event_wait
//============================================================
int osd_event_wait(osd_event *event, osd_ticks_t timeout)
{
pthread_mutex_lock(&event->mutex);
if (!timeout)
{
if (!event->signalled)
{
pthread_cond_wait(&event->cond, &event->mutex);
}
}
else
{
struct timespec ts;
struct timeval tp;
gettimeofday(&tp, NULL);
ts.tv_sec = tp.tv_sec;
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec += timeout / osd_ticks_per_second();
if (!event->signalled)
if ( pthread_cond_timedwait(&event->cond, &event->mutex, &ts) != 0 )
return FALSE;
}
if (event->autoreset)
event->signalled = 0;
pthread_mutex_unlock(&event->mutex);
return TRUE;
}
- pthread_mutex_destroy(&mutex->id);
- free(mutex);
//============================================================
// osd_atomic_lock
//============================================================
void osd_atomic_lock(void)
{
if (!atomic_lck)
atomic_lck = osd_lock_alloc();
osd_lock_acquire(atomic_lck);
}
//============================================================
// osd_atomic_unlock
//============================================================
void osd_atomic_unlock(void)
{
osd_lock_release(atomic_lck);
}
//============================================================
// osd_thread_create
//============================================================
osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam)
{
osd_thread *thread;
thread = (osd_thread *)calloc(1, sizeof(osd_thread));
if ( pthread_create(&thread->thread, NULL, callback, cbparam) != 0 )
{
free(thread);
return NULL;
}
return thread;
}
//============================================================
// osd_thread_adjust_priority
//============================================================
int osd_thread_adjust_priority(osd_thread *thread, int adjust)
{
struct sched_param sched;
int policy;
if ( pthread_getschedparam( thread->thread, &policy, &sched ) == 0 )
{
sched.sched_priority += adjust;
if ( pthread_setschedparam(thread->thread, policy, &sched ) == 0)
return TRUE;
else
return FALSE;
}
else
return FALSE;
}
//============================================================
// osd_thread_wait_free
//============================================================
void osd_thread_wait_free(osd_thread *thread)
{
pthread_join(thread->thread, NULL);
free(thread);
}
Here are prototypes and inline functions for sdlsync.h
/***************************************************************************
SYNCHRONIZATION INTERFACES - Events
***************************************************************************/
/* osd_event is an opaque type which represents a setable/resetable event */
typedef struct _osd_event osd_event;
/*-----------------------------------------------------------------------------
osd_lock_event_alloc: allocate a new event
Parameters:
manualreset - boolean. If true, the event will be automatically set
to non-signalled after a thread successfully waited for
it.
initialstate - boolean. If true, the event is signalled initially.
Return value:
A pointer to the allocated event.
-----------------------------------------------------------------------------*/
osd_event *osd_event_alloc(int manualreset, int initialstate);
/*-----------------------------------------------------------------------------
osd_event_wait: wait for an event to be signalled
Parameters:
event - The event to wait for. If the event is in signalled state, the
function returns immediately. If not it will wait for the event
to become signalled.
timeout - timeout in osd_ticks
Return value:
TRUE: The event was signalled
FALSE: A timeout occurred
-----------------------------------------------------------------------------*/
int osd_event_wait(osd_event *event, osd_ticks_t timeout);
/*-----------------------------------------------------------------------------
osd_event_reset: reset an event to non-signalled state
Parameters:
event - The event to set to non-signalled state
Return value:
None
-----------------------------------------------------------------------------*/
void osd_event_reset(osd_event *event);
/*-----------------------------------------------------------------------------
osd_event_set: set an event to signalled state
Parameters:
event - The event to set to signalled state
Return value:
None
Notes:
All threads waiting for the event will be signalled.
-----------------------------------------------------------------------------*/
void osd_event_set(osd_event *event);
/*-----------------------------------------------------------------------------
osd_event_free: free the memory and resources associated with an osd_event
Parameters:
event - a pointer to a previously allocated osd_event.
Return value:
None.
-----------------------------------------------------------------------------*/
void osd_event_free(osd_event *event);
/***************************************************************************
SYNCHRONIZATION INTERFACES - Threads
***************************************************************************/
/* osd_thread is an opaque type which represents a thread */
typedef struct _osd_thread osd_thread;
/* osd_thread_callback is a callback function that will be called from the thread */
typedef void *(*osd_thread_callback)(void *param);
/*-----------------------------------------------------------------------------
osd_thread_create: create a new thread
Parameters:
callback - The callback function to be called once the thread is up
cbparam - The parameter to pass to the callback function.
Return value:
A pointer to the created thread.
-----------------------------------------------------------------------------*/
osd_thread *osd_thread_create(osd_thread_callback callback, void *cbparam);
/*-----------------------------------------------------------------------------
osd_thread_adjust_priority: adjust priority of a thread
Parameters:
thread - A pointer to a previously created thread.
adjust - signed integer to add to the thread priority
Return value:
TRUE on success, FALSE on failure
-----------------------------------------------------------------------------*/
int osd_thread_adjust_priority(osd_thread *thread, int adjust);
/*-----------------------------------------------------------------------------
osd_thread_wait_free: wait for thread to finish and free resources
Parameters:
thread - A pointer to a previously created thread.
Return value:
None.
-----------------------------------------------------------------------------*/
void osd_thread_wait_free(osd_thread *thread);
/*-----------------------------------------------------------------------------
osd_num_processors: return the number of processors
Parameters:
None.
Return value:
Number of processors
-----------------------------------------------------------------------------*/
int osd_num_processors(void);
/*-----------------------------------------------------------------------------
osd_atomic_lock: block other processes
Parameters:
None.
Return value:
None.
Notes:
This will be used on certain platforms to emulate atomic operations
Please see osinclude.h
-----------------------------------------------------------------------------*/
void osd_atomic_lock(void);
/*-----------------------------------------------------------------------------
osd_atomic_unlock: unblock other processes
Parameters:
None.
Return value:
None.
Notes:
This will be used on certain platforms to emulate atomic operations
Please see osinclude.h
-----------------------------------------------------------------------------*/
void osd_atomic_unlock(void);
Using these functions in sdlwork.c should make the code look a lot more like the windows equivalent and consequently make implementing further changes easier. BTW: If there is interest, I still have the windows equivalents around as well. I may have some time on the weekend to look into this. If somebody is already working on it, please let me know!
|
|
|
|
Joined: Feb 2004
Posts: 2,608 Likes: 315
Very Senior Member
|
Very Senior Member
Joined: Feb 2004
Posts: 2,608 Likes: 315 |
I'll have a look at it... edit: well, I'll have to call it a night. I worked your abstractions into sdlsync.c, couriersud, and changed as much of sdlwork.c to use it as possible. However, there's one place where Aaron calls WaitForMultipleObjects on three event handles, and there's no simple way to simulate that with pthreads condition variables. You can get my modified files here.
Last edited by Vas Crabb; 10/06/07 01:30 PM.
|
|
|
|
Joined: Feb 2007
Posts: 507
Senior Member
|
Senior Member
Joined: Feb 2007
Posts: 507 |
Vas, thanks a lot for the update. I combined it with some work I started, put in a ugly hack for the "wait_for_multiple_objects" and fixed a bug in the code I posted previously (timeout section of osd_event_wait). The result may be found here . Only tested with a debug symbol build, but radikalb works in -mt as well as dkong and galaxian. In the end, osd_compare_exchange32/64 should be inline functions in osinline.h, but for now it just works. More later.
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
The new work queue functionality is used by the 3dfx emulation, so something like gradius4 would be the real test. Regardless, thanks to both of you and I'll check out the work.
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
Ok, sorry for doubting you, Gradius 4 works great, and with OSDPROCESSORS cranked it's quite a bit faster - once we get a DRC for the PowerPC on the new framework it may well run 100% all the time on my system :-)
|
|
|
1 members (1 invisible),
57
guests, and
2
robots. |
Key:
Admin,
Global Mod,
Mod
|
|
Forums9
Topics9,331
Posts122,197
Members5,077
|
Most Online1,283 Dec 21st, 2022
|
|
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!
|
|
|
|