Previous Thread
Next Thread
Print Thread
Page 1 of 10 1 2 3 9 10
Joined: Mar 2001
Posts: 17,239
Likes: 263
R
Very Senior Member
Very Senior Member
R Offline
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
C
Senior Member
Senior Member
C Offline
Joined: Feb 2007
Posts: 507
Originally Posted by R. Belmont
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.

Code
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
R
Very Senior Member
Very Senior Member
R Offline
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
R
Very Senior Member
Very Senior Member
R Offline
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
C
Senior Member
Senior Member
C Offline
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

Code
 #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

Code
/***************************************************************************
    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
C
Senior Member
Senior Member
C Offline
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
R
Very Senior Member
Very Senior Member
R Offline
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
R
Very Senior Member
Very Senior Member
R Offline
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 :-)

Page 1 of 10 1 2 3 9 10

Moderated by  R. Belmont 

Link Copied to Clipboard
Who's Online Now
1 members (1 invisible), 57 guests, and 2 robots.
Key: Admin, Global Mod, Mod
ShoutChat
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics9,331
Posts122,197
Members5,077
Most Online1,283
Dec 21st, 2022
Our Sponsor
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!

Superior Solitaire
Powered by UBB.threads™ PHP Forum Software 8.0.0