List:Commits« Previous MessageNext Message »
From:Vladislav Vaintroub Date:September 27 2010 7:38pm
Subject:bzr commit into mysql-5.5-bugfixing branch (vvaintroub:3204)
View as plain text  
#At file:///H:/bzr-new/55bf/ based on revid:mats.kindahl@stripped

 3204 Vladislav Vaintroub	2010-09-27
      Use native windows conditions and rwlocks i mysys if available.
      
      This patch is intended to be applied  on top of 
      dlenev's prlock patch.
      
      rwlocks used here do not implement extra properties required by runtime 
      team, commonly knows as "readers preference" ( which in detail means
      starving writer, recursive read acquires, serialization of unlock 
      calls and perhaps more).
      
      Also , since this patch is using pthread_once heavily, optimize it to save
      and interlocked operation in case once routine has already finished.

    modified:
      include/my_pthread.h
      mysys/my_wincond.c
      mysys/my_winthread.c
      mysys/thr_rwlock.c
=== modified file 'include/my_pthread.h'
--- a/include/my_pthread.h	2010-08-10 21:12:01 +0000
+++ b/include/my_pthread.h	2010-09-27 19:38:44 +0000
@@ -49,6 +49,7 @@ typedef struct st_pthread_link {
 } pthread_link;
 
 typedef struct {
+  CONDITION_VARIABLE native_cond; /*native condition (Vista and later) */
   uint32 waiting;
   CRITICAL_SECTION lock_waiting;
  
@@ -651,6 +652,10 @@ extern int rw_pr_init(struct st_my_rw_lo
   read/write locks which prefer readers we have to use own implementation.
 */
 typedef struct st_my_rw_lock_t {
+#ifdef _WIN32
+	SRWLOCK srwlock;            /* native rwlock (Vista and later) */
+	BOOL have_exclusive_srwlock;   /* used for unlock */
+#endif
 	pthread_mutex_t lock;		/* lock for structure		*/
 	pthread_cond_t	readers;	/* waiting readers		*/
 	pthread_cond_t	writers;	/* waiting writers		*/

=== modified file 'mysys/my_wincond.c'
--- a/mysys/my_wincond.c	2009-11-23 17:08:37 +0000
+++ b/mysys/my_wincond.c	2010-09-27 19:38:44 +0000
@@ -24,7 +24,107 @@
 #include <process.h>
 #include <sys/timeb.h>
 
-int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+
+/* Windows native condition variables. We use runtime loading / function 
+  pointers, because they are not available on XP */
+
+/* Prototypes and function pointers for condition variable functions */
+typedef VOID (WINAPI * InitializeConditionVariableProc) 
+  (PCONDITION_VARIABLE ConditionVariable);
+static InitializeConditionVariableProc my_InitializeConditionVariable;
+
+typedef BOOL (WINAPI * SleepConditionVariableCSProc)
+  (PCONDITION_VARIABLE ConditionVariable,
+  PCRITICAL_SECTION CriticalSection, 
+  DWORD dwMilliseconds);
+static SleepConditionVariableCSProc my_SleepConditionVariableCS;
+
+typedef VOID (WINAPI * WakeAllConditionVariableProc)
+ (PCONDITION_VARIABLE ConditionVariable);
+static WakeAllConditionVariableProc my_WakeAllConditionVariable;
+
+typedef VOID (WINAPI * WakeConditionVariableProc)
+  (PCONDITION_VARIABLE ConditionVariable);
+static WakeConditionVariableProc my_WakeConditionVariable;
+
+
+/**
+ Indicates if we have native condition variables,
+ initialized first time pthread_cond_init is called.
+*/
+static BOOL have_native_conditions= FALSE;
+
+/* Old condition implementation (pre-Vista) */
+static int legacy_cond_init(pthread_cond_t *, const pthread_condattr_t *);
+static int legacy_cond_destroy(pthread_cond_t *);
+static int legacy_cond_signal(pthread_cond_t *);
+static int legacy_cond_broadcast(pthread_cond_t *);
+static int legacy_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, 
+  struct timespec *);
+
+
+/**
+  Check if native conditions can be used, load function pointers 
+*/
+static void check_native_cond_availability(void)
+{
+  HMODULE module= GetModuleHandle("kernel32");
+
+  my_InitializeConditionVariable = (InitializeConditionVariableProc)
+    GetProcAddress(module, "InitializeConditionVariable");
+  my_SleepConditionVariableCS= (SleepConditionVariableCSProc)
+    GetProcAddress(module, "SleepConditionVariableCS");
+  my_WakeAllConditionVariable= (WakeAllConditionVariableProc)
+    GetProcAddress(module, "WakeAllConditionVariable");
+  my_WakeConditionVariable= (WakeConditionVariableProc)
+    GetProcAddress(module, "WakeConditionVariable");
+
+  if(my_InitializeConditionVariable)
+    have_native_conditions = TRUE;
+}
+
+/**
+  Convert abstime to milliseconds
+*/
+static DWORD get_milliseconds(const struct timespec *abstime)
+{
+  long long millis; 
+  union ft64 now;
+
+  if(abstime == NULL)
+   return INFINITE;
+
+  GetSystemTimeAsFileTime(&now.ft);
+
+  /*
+    Calculate time left to abstime
+    - subtract start time from current time(values are in 100ns units)
+    - convert to millisec by dividing with 10000
+  */
+  millis = (abstime->tv.i64 - now.i64) / 10000;
+  
+  /* Don't allow the timeout to be negative */
+  if (millis < 0)
+    return 0;
+
+  /*
+    Make sure the calucated timeout does not exceed original timeout
+    value which could cause "wait for ever" if system time changes
+  */
+  if (millis > abstime->max_timeout_msec)
+    millis= abstime->max_timeout_msec;
+  
+  if (millis > UINT_MAX)
+    millis= UINT_MAX;
+
+  return (DWORD)millis;
+}
+
+
+/*
+  Old (pre-vista) implementation using events
+*/
+static int legacy_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
 {
   cond->waiting= 0;
   InitializeCriticalSection(&cond->lock_waiting);
@@ -53,7 +153,8 @@ int pthread_cond_init(pthread_cond_t *co
   return 0;
 }
 
-int pthread_cond_destroy(pthread_cond_t *cond)
+
+static int legacy_cond_destroy(pthread_cond_t *cond)
 {
   DeleteCriticalSection(&cond->lock_waiting);
 
@@ -65,48 +166,13 @@ int pthread_cond_destroy(pthread_cond_t 
 }
 
 
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
-{
-  return pthread_cond_timedwait(cond,mutex,NULL);
-}
-
-
-int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+static int legacy_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
                            struct timespec *abstime)
 {
   int result;
   long timeout; 
-  union ft64 now;
-
-  if( abstime != NULL )
-  {
-    GetSystemTimeAsFileTime(&now.ft);
-
-    /*
-      Calculate time left to abstime
-      - subtract start time from current time(values are in 100ns units)
-      - convert to millisec by dividing with 10000
-    */
-    timeout= (long)((abstime->tv.i64 - now.i64) / 10000);
-    
-    /* Don't allow the timeout to be negative */
-    if (timeout < 0)
-      timeout= 0L;
-
-    /*
-      Make sure the calucated timeout does not exceed original timeout
-      value which could cause "wait for ever" if system time changes
-    */
-    if (timeout > abstime->max_timeout_msec)
-      timeout= abstime->max_timeout_msec;
-
-  }
-  else
-  {
-    /* No time specified; don't expire */
-    timeout= INFINITE;
-  }
 
+  timeout= get_milliseconds(abstime);
   /* 
     Block access if previous broadcast hasn't finished.
     This is just for safety and should normally not
@@ -142,7 +208,7 @@ int pthread_cond_timedwait(pthread_cond_
   return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
 }
 
-int pthread_cond_signal(pthread_cond_t *cond)
+static int legacy_cond_signal(pthread_cond_t *cond)
 {
   EnterCriticalSection(&cond->lock_waiting);
   
@@ -155,7 +221,7 @@ int pthread_cond_signal(pthread_cond_t *
 }
 
 
-int pthread_cond_broadcast(pthread_cond_t *cond)
+static int legacy_cond_broadcast(pthread_cond_t *cond)
 {
   EnterCriticalSection(&cond->lock_waiting);
   /*
@@ -177,6 +243,80 @@ int pthread_cond_broadcast(pthread_cond_
 }
 
 
+/* 
+ Posix API functions just chose between native and legacy implementation 
+*/
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+  /* check if native conditions are available on the first call */
+  static my_pthread_once_t once_control = MY_PTHREAD_ONCE_INIT;
+  my_pthread_once(&once_control, check_native_cond_availability);
+
+  if(have_native_conditions)
+  {
+	my_InitializeConditionVariable(&cond->native_cond);
+	return 0;
+  }
+  else 
+    return legacy_cond_init(cond, attr);
+}
+
+
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+  if(have_native_conditions)
+    return 0; /* no destroy function */
+  else
+    return legacy_cond_destroy(cond);
+}
+
+
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+  if(have_native_conditions)
+  {
+    my_WakeAllConditionVariable(&cond->native_cond);
+    return 0;
+  }
+  else
+    return legacy_cond_broadcast(cond);
+}
+
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+  if(have_native_conditions)
+  {
+    my_WakeConditionVariable(&cond->native_cond);
+    return 0;
+  }
+  else
+    return legacy_cond_signal(cond);
+}
+
+
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+  struct timespec *abstime)
+{
+  if(have_native_conditions)
+  {
+    DWORD timeout= get_milliseconds(abstime);
+    if(!my_SleepConditionVariableCS(&cond->native_cond, mutex, timeout))
+      return ETIMEDOUT;
+    return 0;  
+  }
+  else
+    return legacy_cond_timedwait(cond, mutex, abstime);
+}
+
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+  return pthread_cond_timedwait(cond, mutex, NULL);
+}
+
+
 int pthread_attr_init(pthread_attr_t *connect_att)
 {
   connect_att->dwStackSize	= 0;

=== modified file 'mysys/my_winthread.c'
--- a/mysys/my_winthread.c	2009-12-19 13:11:48 +0000
+++ b/mysys/my_winthread.c	2010-09-27 19:38:44 +0000
@@ -155,6 +155,13 @@ int pthread_cancel(pthread_t thread)
 int my_pthread_once(my_pthread_once_t *once_control, 
     void (*init_routine)(void))
 {
+  /*
+    Do "dirty" read to find out if initialization is already done, to
+    save an interlocked operation in common case.
+  */
+  if (*once_control == MY_PTHREAD_ONCE_DONE)
+    return 0;
+
   LONG state= InterlockedCompareExchange(once_control, MY_PTHREAD_ONCE_INPROGRESS,
                                           MY_PTHREAD_ONCE_INIT);
   switch(state)

=== modified file 'mysys/thr_rwlock.c'
--- a/mysys/thr_rwlock.c	2010-08-12 13:50:23 +0000
+++ b/mysys/thr_rwlock.c	2010-09-27 19:38:44 +0000
@@ -20,6 +20,131 @@
 #if defined(NEED_MY_RW_LOCK)
 #include <errno.h>
 
+#ifdef _WIN32
+
+/* 
+  Use native windows slim reader writer lock if possible (Vista and later).
+  Check presence of rwlock functions at runtime, and load them dynamically.
+  Fallback to portable implementation on older Windows.
+*/
+
+static BOOL have_srwlock = TRUE;
+/* Prototypes and function pointers for windows  functions */
+typedef VOID (WINAPI* srw_func) (PSRWLOCK SRWLock);
+typedef BOOL (WINAPI* srw_bool_func) (PSRWLOCK SRWLock);
+
+static srw_func my_InitializeSRWLock;
+static srw_func my_AcquireSRWLockExclusive;
+static srw_func my_ReleaseSRWLockExclusive;
+static srw_func my_AcquireSRWLockShared;
+static srw_func my_ReleaseSRWLockShared;
+
+static srw_bool_func my_TryAcquireSRWLockExclusive;
+static srw_bool_func my_TryAcquireSRWLockShared;
+
+/**
+  Check for presence of Windows slim reader writer lock function
+  (available in Vista and later). Load function pointers.
+*/
+static void check_srwlock_availability(void)
+{
+  HMODULE module= GetModuleHandle("kernel32");
+
+  my_InitializeSRWLock= (srw_func) GetProcAddress(module,
+    "InitializeSRWLock");
+  my_AcquireSRWLockExclusive= (srw_func) GetProcAddress(module,
+    "AcquireSRWLockExclusive");
+  my_AcquireSRWLockShared= (srw_func) GetProcAddress(module,
+    "AcquireSRWLockShared");
+  my_ReleaseSRWLockExclusive= (srw_func) GetProcAddress(module,
+    "ReleaseSRWLockExclusive");
+  my_ReleaseSRWLockShared= (srw_func) GetProcAddress(module,
+    "ReleaseSRWLockShared");
+  my_TryAcquireSRWLockExclusive=  (srw_bool_func) GetProcAddress(module,
+    "TryAcquireSRWLockExclusive");
+  my_TryAcquireSRWLockShared=  (srw_bool_func) GetProcAddress(module,
+    "TryAcquireSRWLockShared");
+  if(my_InitializeSRWLock)
+    have_srwlock= TRUE;
+}
+
+
+static int srw_init(my_rw_lock_t *rwp)
+{
+  my_InitializeSRWLock(&rwp->srwlock);
+  rwp->have_exclusive_srwlock = FALSE;
+  return 0;
+}
+
+
+static int srw_rdlock(my_rw_lock_t *rwp)
+{
+  my_AcquireSRWLockShared(&rwp->srwlock);
+  DBUG_ASSERT(!rwp->have_exclusive_srwlock);
+  return 0;
+}
+
+
+static int srw_tryrdlock(my_rw_lock_t *rwp)
+{
+  /* TryAcquire is new in Win7, use if available */
+  if(my_TryAcquireSRWLockShared)
+  {
+    if(!my_TryAcquireSRWLockShared(&rwp->srwlock))
+      return EBUSY;
+  }
+  else
+  {
+    /* Try harder, actually acquire the lock */
+    my_AcquireSRWLockShared(&rwp->srwlock);
+  }
+  DBUG_ASSERT(!rwp->have_exclusive_srwlock);
+  return 0;
+}
+
+
+static int srw_wrlock(my_rw_lock_t *rwp)
+{
+  my_AcquireSRWLockExclusive(&rwp->srwlock);
+  rwp->have_exclusive_srwlock= TRUE;
+  return 0;
+}
+
+
+static int srw_trywrlock(my_rw_lock_t *rwp)
+{
+  /* TryAcquire is new in Win7, use it if available */
+  if(my_TryAcquireSRWLockExclusive)
+  {
+    if(!my_TryAcquireSRWLockExclusive(&rwp->srwlock))
+      return EBUSY;
+  }
+  else
+  {
+     /* Try harder, actually acquire the lock */
+     my_AcquireSRWLockExclusive(&rwp->srwlock);
+  }
+  rwp->have_exclusive_srwlock= TRUE;
+  return 0;
+}
+
+
+static int srw_unlock(my_rw_lock_t *rwp)
+{
+  if(rwp->have_exclusive_srwlock)
+  {
+    rwp->have_exclusive_srwlock= FALSE;
+    my_ReleaseSRWLockExclusive(&rwp->srwlock);
+  }
+  else
+  {
+    my_ReleaseSRWLockShared(&rwp->srwlock);
+  }
+  return 0;
+}
+
+#endif
+
 /*
   Source base from Sun Microsystems SPILT, simplified for MySQL use
   -- Joshua Chamas
@@ -63,6 +188,18 @@ int my_rw_init(my_rw_lock_t *rwp, my_boo
 {
   pthread_condattr_t	cond_attr;
 
+#ifdef _WIN32
+  /* 
+    Check if slim reader writer lock available on the first call
+    to init.
+ */
+  static my_pthread_once_t once_control= MY_PTHREAD_ONCE_INIT;
+  my_pthread_once(&once_control, check_srwlock_availability);
+
+  if(have_srwlock)
+    return srw_init(rwp);
+#endif
+
   pthread_mutex_init( &rwp->lock, MY_MUTEX_INIT_FAST);
   pthread_condattr_init( &cond_attr );
   pthread_cond_init( &rwp->readers, &cond_attr );
@@ -83,6 +220,10 @@ int my_rw_init(my_rw_lock_t *rwp, my_boo
 
 int my_rw_destroy(my_rw_lock_t *rwp)
 {
+#ifdef _WIN32
+  if(have_srwlock)
+    return 0; /* no destroy function */
+#endif
   DBUG_ASSERT(rwp->state == 0);
   pthread_mutex_destroy( &rwp->lock );
   pthread_cond_destroy( &rwp->readers );
@@ -93,6 +234,11 @@ int my_rw_destroy(my_rw_lock_t *rwp)
 
 int my_rw_rdlock(my_rw_lock_t *rwp)
 {
+#ifdef _WIN32
+  if(have_srwlock)
+    return srw_rdlock(rwp);
+#endif
+
   pthread_mutex_lock(&rwp->lock);
 
   /* active or queued writers */
@@ -108,6 +254,12 @@ int my_rw_rdlock(my_rw_lock_t *rwp)
 int my_rw_tryrdlock(my_rw_lock_t *rwp)
 {
   int res;
+
+#ifdef _WIN32
+  if(have_srwlock)
+    return srw_tryrdlock(rwp);
+#endif
+
   pthread_mutex_lock(&rwp->lock);
   if ((rwp->state < 0 ) ||
       (rwp->waiters && ! rwp->prefer_readers))
@@ -124,6 +276,11 @@ int my_rw_tryrdlock(my_rw_lock_t *rwp)
 
 int my_rw_wrlock(my_rw_lock_t *rwp)
 {
+#ifdef _WIN32
+  if(have_srwlock)
+    return srw_wrlock(rwp);
+#endif
+
   pthread_mutex_lock(&rwp->lock);
   rwp->waiters++;				/* another writer queued */
 
@@ -144,6 +301,12 @@ int my_rw_wrlock(my_rw_lock_t *rwp)
 int my_rw_trywrlock(my_rw_lock_t *rwp)
 {
   int res;
+
+#ifdef _WIN32
+  if(have_srwlock)
+    return srw_trywrlock(rwp);
+#endif
+
   pthread_mutex_lock(&rwp->lock);
   if (rwp->state)
     res= EBUSY;					/* Can't get lock */    
@@ -162,6 +325,11 @@ int my_rw_trywrlock(my_rw_lock_t *rwp)
 
 int my_rw_unlock(my_rw_lock_t *rwp)
 {
+#ifdef _WIN32
+  if(have_srwlock)
+    return srw_unlock(rwp);
+#endif
+
   DBUG_PRINT("rw_unlock",
 	     ("state: %d waiters: %d", rwp->state, rwp->waiters));
   pthread_mutex_lock(&rwp->lock);


Attachment: [text/bzr-bundle] bzr/vvaintroub@mysql.com-20100927193844-r915h6n03jne3am2.bundle
Thread
bzr commit into mysql-5.5-bugfixing branch (vvaintroub:3204) Vladislav Vaintroub27 Sep
Re: bzr commit into mysql-5.5-bugfixing branch (vvaintroub:3204)Davi Arnaut1 Oct
Re: bzr commit into mysql-5.5-bugfixing branch (vvaintroub:3204)Dmitry Lenev1 Oct
  • RE: bzr commit into mysql-5.5-bugfixing branch (vvaintroub:3204)Vladislav Vaintroub1 Oct
    • Re: bzr commit into mysql-5.5-bugfixing branch (vvaintroub:3204)Dmitry Lenev1 Oct