Commit 87ecdf32 authored by unknown's avatar unknown

BUG#30992 (Wrong implementation of pthread_mutex_trylock()):

Adding support for correct handling of pthread_mutex_trylock() on Win32
systems as well as when using the safe mutexes. 


include/my_pthread.h:
  Adding win_pthread_mutex_trylock() function as wrapper function for
  Windows implementation of pthread_mutex_trylock().
  
  Adding flag to safe_mutex_lock() that is shall not abort if the mutex
  is already locked and instead return EBUSY since this is the POSIX
  behaviour.
mysys/my_winthread.c:
  Added Win32 wrappper function to handle pthread_mutex_trylock().
mysys/thr_mutex.c:
  Added parameter 'try_lock' to safe_mutex_lock() to allow it to do double-
  duty as a pthread_mutex_trylock() in addition to working as
  pthread_mutex_lock().
  
  The code needs to return EBUSY instead of throwing an error in the event
  that the mutex is re-locked (we do not have recursive mutexes), but it
  also requires some special handling to avoid race conditions when
  calling the real pthread_mutex_{lock,trylock}().
parent 6de5bc20
...@@ -135,6 +135,7 @@ struct timespec { ...@@ -135,6 +135,7 @@ struct timespec {
void win_pthread_init(void); void win_pthread_init(void);
int win_pthread_setspecific(void *A,void *B,uint length); int win_pthread_setspecific(void *A,void *B,uint length);
int win_pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *); int pthread_create(pthread_t *,pthread_attr_t *,pthread_handler,void *);
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
...@@ -195,7 +196,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *); ...@@ -195,7 +196,7 @@ extern int pthread_mutex_destroy (pthread_mutex_t *);
#else #else
#define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0) #define pthread_mutex_init(A,B) (InitializeCriticalSection(A),0)
#define pthread_mutex_lock(A) (EnterCriticalSection(A),0) #define pthread_mutex_lock(A) (EnterCriticalSection(A),0)
#define pthread_mutex_trylock(A) (WaitForSingleObject((A), 0) == WAIT_TIMEOUT) #define pthread_mutex_trylock(A) win_pthread_mutex_trylock((A))
#define pthread_mutex_unlock(A) LeaveCriticalSection(A) #define pthread_mutex_unlock(A) LeaveCriticalSection(A)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A) #define pthread_mutex_destroy(A) DeleteCriticalSection(A)
#define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B)) #define my_pthread_setprio(A,B) SetThreadPriority(GetCurrentThread(), (B))
...@@ -593,7 +594,7 @@ typedef struct st_safe_mutex_info_t ...@@ -593,7 +594,7 @@ typedef struct st_safe_mutex_info_t
int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr, int safe_mutex_init(safe_mutex_t *mp, const pthread_mutexattr_t *attr,
const char *file, uint line); const char *file, uint line);
int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line);
int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line);
int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line); int safe_mutex_destroy(safe_mutex_t *mp,const char *file, uint line);
int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file, int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp,const char *file,
...@@ -616,12 +617,12 @@ void safe_mutex_end(FILE *file); ...@@ -616,12 +617,12 @@ void safe_mutex_end(FILE *file);
#undef pthread_cond_timedwait #undef pthread_cond_timedwait
#undef pthread_mutex_trylock #undef pthread_mutex_trylock
#define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__) #define pthread_mutex_init(A,B) safe_mutex_init((A),(B),__FILE__,__LINE__)
#define pthread_mutex_lock(A) safe_mutex_lock((A),__FILE__,__LINE__) #define pthread_mutex_lock(A) safe_mutex_lock((A), FALSE, __FILE__, __LINE__)
#define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__) #define pthread_mutex_unlock(A) safe_mutex_unlock((A),__FILE__,__LINE__)
#define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__) #define pthread_mutex_destroy(A) safe_mutex_destroy((A),__FILE__,__LINE__)
#define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__) #define pthread_cond_wait(A,B) safe_cond_wait((A),(B),__FILE__,__LINE__)
#define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) #define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__)
#define pthread_mutex_trylock(A) pthread_mutex_lock(A) #define pthread_mutex_trylock(A) safe_mutex_lock((A), TRUE, __FILE__, __LINE__)
#define pthread_mutex_t safe_mutex_t #define pthread_mutex_t safe_mutex_t
#define safe_mutex_assert_owner(mp) \ #define safe_mutex_assert_owner(mp) \
DBUG_ASSERT((mp)->count > 0 && \ DBUG_ASSERT((mp)->count > 0 && \
......
...@@ -40,6 +40,31 @@ void win_pthread_init(void) ...@@ -40,6 +40,31 @@ void win_pthread_init(void)
pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST); pthread_mutex_init(&THR_LOCK_thread,MY_MUTEX_INIT_FAST);
} }
/**
Adapter to @c pthread_mutex_trylock()
@retval 0 Mutex was acquired
@retval EBUSY Mutex was already locked by a thread
@retval EINVAL Mutex could not be acquired due to other error
*/
int
win_pthread_mutex_trylock(pthread_mutex_t *mutex)
{
switch (WaitForSingleObject(mutex, 0)) {
case WAIT_TIMEOUT:
return EBUSY;
default:
case WAIT_FAILURE:
return EINVAL;
case WAIT_OBJECT_0:
case WAIT_ABANDONED: /* The mutex was acquired because it was
* abandoned */
return 0;
}
}
/* /*
** We have tried to use '_beginthreadex' instead of '_beginthread' here ** We have tried to use '_beginthreadex' instead of '_beginthread' here
** but in this case the program leaks about 512 characters for each ** but in this case the program leaks about 512 characters for each
......
...@@ -91,7 +91,7 @@ int safe_mutex_init(safe_mutex_t *mp, ...@@ -91,7 +91,7 @@ int safe_mutex_init(safe_mutex_t *mp,
} }
int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line) int safe_mutex_lock(safe_mutex_t *mp, my_bool try_lock, const char *file, uint line)
{ {
int error; int error;
if (!mp->file) if (!mp->file)
...@@ -104,15 +104,50 @@ int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line) ...@@ -104,15 +104,50 @@ int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
} }
pthread_mutex_lock(&mp->global); pthread_mutex_lock(&mp->global);
if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread)) if (mp->count > 0)
{ {
fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d in thread %s\n", if (try_lock)
{
pthread_mutex_unlock(&mp->global);
return EBUSY;
}
else if (pthread_equal(pthread_self(),mp->thread))
{
fprintf(stderr,
"safe_mutex: Trying to lock mutex at %s, line %d, when the"
" mutex was already locked at %s, line %d in thread %s\n",
file,line,mp->file, mp->line, my_thread_name()); file,line,mp->file, mp->line, my_thread_name());
fflush(stderr); fflush(stderr);
abort(); abort();
} }
}
pthread_mutex_unlock(&mp->global); pthread_mutex_unlock(&mp->global);
error=pthread_mutex_lock(&mp->mutex);
/*
If we are imitating trylock(), we need to take special
precautions.
- We cannot use pthread_mutex_lock() only since another thread can
overtake this thread and take the lock before this thread
causing pthread_mutex_trylock() to hang. In this case, we should
just return EBUSY. Hence, we use pthread_mutex_trylock() to be
able to return immediately.
- We cannot just use trylock() and continue execution below, since
this would generate an error and abort execution if the thread
was overtaken and trylock() returned EBUSY . In this case, we
instead just return EBUSY, since this is the expected behaviour
of trylock().
*/
if (try_lock)
{
error= pthread_mutex_trylock(&mp->mutex);
if (error == EBUSY)
return error;
}
else
error= pthread_mutex_lock(&mp->mutex);
if (error || (error=pthread_mutex_lock(&mp->global))) if (error || (error=pthread_mutex_lock(&mp->global)))
{ {
fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n", fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment