SDL_TryLockMutex

The following patch adds a new SDL_TryLockMutex() API function to SDL. I hope I
did it right, so let me know if you see anything wrong. I’m not sure how it’s
suppose to behave for recursive mutexes…–
Stephane Peter
Programmer
Loki Entertainment Software

“Microsoft has done to computers what McDonald’s has done to gastronomy”
-------------- next part --------------
Index: include/SDL_mutex.h

RCS file: /cvs/SDL/include/SDL_mutex.h,v
retrieving revision 1.5.2.5
diff -u -r1.5.2.5 SDL_mutex.h
— include/SDL_mutex.h 2000/04/21 02:16:34 1.5.2.5
+++ include/SDL_mutex.h 2000/05/09 22:28:09
@@ -66,6 +66,11 @@
#define SDL_LockMutex(m) SDL_mutexP(m)
extern DECLSPEC int SDL_mutexP(SDL_mutex *mutex);

+/* Try to lock the mutex: returns 0 if succeeded, -1 on error,

  • and SDL_MUTEX_TIMEOUT if the mutex is already locked
  • */
    +extern DECLSPEC int SDL_TryLockMutex(SDL_mutex *mutex);

/* Unlock the mutex (Returns 0, or -1 on error) */
#define SDL_UnlockMutex(m) SDL_mutexV(m)
extern DECLSPEC int SDL_mutexV(SDL_mutex *mutex);
Index: src/thread/generic/SDL_sysmutex.c

RCS file: /cvs/SDL/src/thread/generic/Attic/SDL_sysmutex.c,v
retrieving revision 1.1.2.4
diff -u -r1.1.2.4 SDL_sysmutex.c
— src/thread/generic/SDL_sysmutex.c 2000/04/21 02:16:34 1.1.2.4
+++ src/thread/generic/SDL_sysmutex.c 2000/05/09 22:28:09
@@ -98,6 +98,32 @@
return 0;
}

+/* Try to lock the mutex */
+int SDL_TryLockMutex(SDL_mutex *mutex)
+{

  • Uint32 this_thread;
  • if ( mutex == NULL ) {
  •   SDL_SetError("Passed a NULL mutex");
    
  •   return -1;
    
  • }
  • this_thread = SDL_ThreadID();
  • if ( mutex->owner ) {
  •   /* Already locked */
    
  •   return SDL_MUTEX_TIMEOUT;
    
  • } else {
  •   /* The order of operations is important.
    
  •      We set the locking thread id after we obtain the lock
    
  •      so unlocks from other threads will fail.
    
  •   */
    
  •   SDL_SemWait(mutex->sem);
    
  •   mutex->owner = this_thread;
    
  •   mutex->recursive = 0;
    
  •   return 0;
    
  • }
    +}

/* Unlock the mutex */
int SDL_mutexV(SDL_mutex *mutex)
{
Index: src/thread/linux/SDL_sysmutex.c

RCS file: /cvs/SDL/src/thread/linux/Attic/SDL_sysmutex.c,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 SDL_sysmutex.c
— src/thread/linux/SDL_sysmutex.c 2000/04/21 02:16:34 1.1.2.3
+++ src/thread/linux/SDL_sysmutex.c 2000/05/09 22:28:09
@@ -130,6 +130,52 @@
return retval;
}

+/* Try to lock the mutex */
+int SDL_TryLockMutex(SDL_mutex *mutex)
+{

  • int retval;
    +#ifdef PTHREAD_NO_RECURSIVE_MUTEX
  • pthread_t this_thread;
    +#endif
  • if ( mutex == NULL ) {
  •   SDL_SetError("Passed a NULL mutex");
    
  •   return -1;
    
  • }

+#ifdef PTHREAD_NO_RECURSIVE_MUTEX

  • this_thread = pthread_self();
  • retval = 0;
  • if ( mutex->owner == this_thread ) {
  •   ++mutex->recursive;
    
  • } else {
  •   switch(pthread_mutex_trylock(&mutex->id)) {
    
  •   case 0:
    
  •   	break;
    
  •   case EBUSY:
    
  •   	retval = SDL_MUTEX_TIMEOUT;
    
  •   	break;
    
  •   default:
    
  •   	SDL_SetError("pthread_mutex_trylock() failed");
    
  •   	retval = -1;
    
  •   }
    
  • }
    +#else
  • switch(pthread_mutex_trylock(&mutex->id)) {
  • case 0:
  •   retval = 0;
    
  •   break;
    
  • case EBUSY:
  •   retval = SDL_MUTEX_TIMEOUT;
    
  •   break;
    
  • default:
  •   SDL_SetError("pthread_mutex_trylock() failed");
    
  •   retval = -1;
    
  • }
    +#endif
  • return retval;
    +}

int SDL_mutexV(SDL_mutex *mutex)
{
int retval;

Stephane Peter wrote:

The following patch adds a new SDL_TryLockMutex() API function to SDL. I hope I
did it right, so let me know if you see anything wrong. I’m not sure how it’s
suppose to behave for recursive mutexes…

If you still have the counter in the mutex struct it behaves
the same.
You cannot increment a counter in the lock call and
then bypass this when directly calling
cond_wait or try_lock. Before doing it you must make sure
that (on success) you decremtn the counter (cond) or inc
for try_lock.

But as I said, better remove the recursive mutexes it can
be really hard to do the recursive approach right.

Martin> –

Stephane Peter
Programmer
Loki Entertainment Software

“Microsoft has done to computers what McDonald’s has done to gastronomy”


                  Name: trylock.diff

trylock.diff Type: Plain Text (text/plain)
Encoding: 7bit
Description: trylock.diff

Stephane Peter wrote:

The following patch adds a new SDL_TryLockMutex() API function to SDL. I hope I
did it right, so let me know if you see anything wrong. I’m not sure how it’s
suppose to behave for recursive mutexes…

The current recursive mutex approach is broken.
I dont like recursive mutex, because they are slower
than “normal” mutexes and lead to "hacks"
You can completley avoid them with a clean design.

But it seems you want them.
So, how it may be possible to implement them
(im not an expert on this, but i have a bit experience)

  • first remove the counter

a single pthread_t for the owner of the mutex
should be ok.
init of owner =NULL.
The owner variable is always mutexed.

Then you can call unlock unlimited times, only
if caller==owner then owner=NULL.
]
on lock owner=caller -> ok, otherwise go lock.

These owner variable must be mutexed by a simple mutex
(obviously you cannot implement recusive mutexe with reusive
mutexes)
Ok, then in ever other call, you can “predict” how it will
behave.
in cond_signal you check owner==caller then owner=null.
because there is only one owner there should be no races.
And then you go sleep on the mutexed owner variable!
(no other mutex needed)
If back ownd=current and then release the mutex of the owner

try_lock is easier.

You should implement the try_wait call with try_lock
and then wait. The semaphore implementation look to
me like a hack, but it may be necessary for other
architectures.
I dont now if try_lock is portable under windows/mac/be
but if you have single mutextes and a working recursive
mutex you can emulate try_lock with them.
its a lock of the mutexed owner, then "predict"
then own=caller and unlock owner mutex.

In short: it seems possible to me to implement
recursive mutex with only a mutex struct like this:

struct rec {
pthread_t owner=0;
pthread_mutex protect:
}

and implemt all other calls based on these.

long mail,

Martin

I dont like recursive mutex, because they are slower
than “normal” mutexes and lead to "hacks"
You can completley avoid them with a clean design.

But it seems you want them.

Actually, I don’t care, but they are recursive on Win32, and the owner
check is necessary with the semaphore implementation anyway to prevent
multiple unlocks from bumping the semaphore more than once.

Okay, so if I understand you correctly, the implementation would
look like this:

recursive_mutex {
owner;
mutex;
count;
}

Lock(m):
if ( m->owner == self ) {
++m->count;
return_ok;
} else {
lock m->mutex;
m->owner = self;
++m->count;
}

Unlock(m)
if ( m->owner == self ) {
–m->count;
if ( m->count == 0 ) {
m->owner = 0;
unlock m->mutex;
}
}

I can’t think of a Trylock() implementation that doesn’t require a separate
protection around m->owner. Hmm, looking back over my semaphore based
implementation, the code above is exactly what is already implemented.
What’s the problem with the above implementation (if no trylock is supported?)

I can’t think of a pure mutex implementation that would support trylock.
The problem is (as I see it) that the obtaining of the lock and the gaining
ownership needs to be atomic, but you can’t hold a mutex protecting the
ownership while waiting for the main mutex, since that would deadlock
threads performing a trywait.

Comments?

-Sam Lantinga, Lead Programmer, Loki Entertainment Software

Sam Lantinga wrote:

I dont like recursive mutex, because they are slower
than “normal” mutexes and lead to "hacks"
You can completley avoid them with a clean design.

But it seems you want them.

Actually, I don’t care, but they are recursive on Win32, and the owner
check is necessary with the semaphore implementation anyway to prevent
multiple unlocks from bumping the semaphore more than once.

Okay, so if I understand you correctly, the implementation would
look like this:

recursive_mutex {
owner;
mutex;
count;
}

Hm, ok.
Forget my last email. This won?t work.

Maybe we need two mutexes?

recursive_mutex {
owner;
mutex_t owner_protect;
mutex_t real_lock;
count;
}

owner protect is a mutex to have an atomic check who is the owner.
real lock is the mutex we wait for if we are not the owner.

hm no.
does not work.
argh.

Why not use an already working thread abstraction lib?
I think there ist one by the FSF, should work everywhere.

Forgot the name, was sometime ago on kde-core-devel.

Martin