src/thread/pthread/SDL_sysmutex.c
author Andreas Schiffler
Sat, 09 Mar 2013 09:24:43 -0800
changeset 6985 a0f905ecdda3
parent 6977 b73d51026c68
child 7037 3fedf1f25b94
permissions -rw-r--r--
Fix SDL_TryLockMutex compile error when FAKE_RECURSIVE_MUTEX is defined
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #define _GNU_SOURCE
    24 #include <pthread.h>
    25 #include <errno.h>
    26 
    27 #include "SDL_thread.h"
    28 
    29 #if !SDL_THREAD_PTHREAD_RECURSIVE_MUTEX && \
    30     !SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP
    31 #define FAKE_RECURSIVE_MUTEX 1
    32 #endif
    33 
    34 struct SDL_mutex
    35 {
    36     pthread_mutex_t id;
    37 #if FAKE_RECURSIVE_MUTEX
    38     int recursive;
    39     pthread_t owner;
    40 #endif
    41 };
    42 
    43 SDL_mutex *
    44 SDL_CreateMutex(void)
    45 {
    46     SDL_mutex *mutex;
    47     pthread_mutexattr_t attr;
    48 
    49     /* Allocate the structure */
    50     mutex = (SDL_mutex *) SDL_calloc(1, sizeof(*mutex));
    51     if (mutex) {
    52         pthread_mutexattr_init(&attr);
    53 #if SDL_THREAD_PTHREAD_RECURSIVE_MUTEX
    54         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    55 #elif SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP
    56         pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
    57 #else
    58         /* No extra attributes necessary */
    59 #endif
    60         if (pthread_mutex_init(&mutex->id, &attr) != 0) {
    61             SDL_SetError("pthread_mutex_init() failed");
    62             SDL_free(mutex);
    63             mutex = NULL;
    64         }
    65     } else {
    66         SDL_OutOfMemory();
    67     }
    68     return (mutex);
    69 }
    70 
    71 void
    72 SDL_DestroyMutex(SDL_mutex * mutex)
    73 {
    74     if (mutex) {
    75         pthread_mutex_destroy(&mutex->id);
    76         SDL_free(mutex);
    77     }
    78 }
    79 
    80 /* Lock the mutex */
    81 int
    82 SDL_LockMutex(SDL_mutex * mutex)
    83 {
    84     int retval;
    85 #if FAKE_RECURSIVE_MUTEX
    86     pthread_t this_thread;
    87 #endif
    88 
    89     if (mutex == NULL) {
    90         SDL_SetError("Passed a NULL mutex");
    91         return -1;
    92     }
    93 
    94     retval = 0;
    95 #if FAKE_RECURSIVE_MUTEX
    96     this_thread = pthread_self();
    97     if (mutex->owner == this_thread) {
    98         ++mutex->recursive;
    99     } else {
   100         /* The order of operations is important.
   101            We set the locking thread id after we obtain the lock
   102            so unlocks from other threads will fail.
   103          */
   104         if (pthread_mutex_lock(&mutex->id) == 0) {
   105             mutex->owner = this_thread;
   106             mutex->recursive = 0;
   107         } else {
   108             SDL_SetError("pthread_mutex_lock() failed");
   109             retval = -1;
   110         }
   111     }
   112 #else
   113     if (pthread_mutex_lock(&mutex->id) < 0) {
   114         SDL_SetError("pthread_mutex_lock() failed");
   115         retval = -1;
   116     }
   117 #endif
   118     return retval;
   119 }
   120 
   121 int
   122 SDL_TryLockMutex(SDL_mutex * mutex)
   123 {
   124     int retval;
   125 #if FAKE_RECURSIVE_MUTEX
   126     pthread_t this_thread;
   127 #endif
   128 
   129     if (mutex == NULL) {
   130         SDL_SetError("Passed a NULL mutex");
   131         return -1;
   132     }
   133 
   134     retval = 0;
   135 #if FAKE_RECURSIVE_MUTEX
   136     this_thread = pthread_self();
   137     if (mutex->owner == this_thread) {
   138         ++mutex->recursive;
   139     } else {
   140         /* The order of operations is important.
   141          We set the locking thread id after we obtain the lock
   142          so unlocks from other threads will fail.
   143          */
   144         if (pthread_mutex_lock(&mutex->id) == 0) {
   145             mutex->owner = this_thread;
   146             mutex->recursive = 0;
   147         } else if (errno == EBUSY) {
   148             retval = SDL_MUTEX_TIMEDOUT;
   149         } else {
   150             SDL_SetError("pthread_mutex_trylock() failed");
   151             retval = -1;
   152         }
   153     }
   154 #else
   155     if (pthread_mutex_trylock(&mutex->id) != 0) {
   156         if (errno == EBUSY) {
   157             retval = SDL_MUTEX_TIMEDOUT;
   158         } else {
   159             SDL_SetError("pthread_mutex_trylock() failed");
   160             retval = -1;
   161         }
   162     }
   163 #endif
   164     return retval;
   165 }
   166 
   167 int
   168 SDL_UnlockMutex(SDL_mutex * mutex)
   169 {
   170     int retval;
   171 
   172     if (mutex == NULL) {
   173         SDL_SetError("Passed a NULL mutex");
   174         return -1;
   175     }
   176 
   177     retval = 0;
   178 #if FAKE_RECURSIVE_MUTEX
   179     /* We can only unlock the mutex if we own it */
   180     if (pthread_self() == mutex->owner) {
   181         if (mutex->recursive) {
   182             --mutex->recursive;
   183         } else {
   184             /* The order of operations is important.
   185                First reset the owner so another thread doesn't lock
   186                the mutex and set the ownership before we reset it,
   187                then release the lock semaphore.
   188              */
   189             mutex->owner = 0;
   190             pthread_mutex_unlock(&mutex->id);
   191         }
   192     } else {
   193         SDL_SetError("mutex not owned by this thread");
   194         retval = -1;
   195     }
   196 
   197 #else
   198     if (pthread_mutex_unlock(&mutex->id) < 0) {
   199         SDL_SetError("pthread_mutex_unlock() failed");
   200         retval = -1;
   201     }
   202 #endif /* FAKE_RECURSIVE_MUTEX */
   203 
   204     return retval;
   205 }
   206 
   207 /* vi: set ts=4 sw=4 expandtab: */