From 7e065ee9ae35e6ac501c1d6a3c06cd83039ab290 Mon Sep 17 00:00:00 2001
From: Mikael Ronstrom <mikael@mysql.com>
Date: Thu, 30 Oct 2008 10:23:36 +0100
Subject: [PATCH] Merge port of Google SMP patch to Solaris

---
 storage/innobase/handler/ha_innodb.cc |  4 ++--
 storage/innobase/include/os0sync.h    |  9 ++++++--
 storage/innobase/include/os0sync.ic   | 30 ++++++++++++++++++---------
 storage/innobase/include/srv0srv.h    |  2 +-
 storage/innobase/include/sync0rw.h    |  4 ++--
 storage/innobase/include/sync0rw.ic   | 16 +++++++-------
 storage/innobase/include/sync0sync.h  |  6 +++++-
 storage/innobase/include/sync0sync.ic |  9 ++++----
 storage/innobase/include/univ.i       |  7 +++++++
 storage/innobase/srv/srv0srv.c        |  6 +++---
 storage/innobase/srv/srv0start.c      |  4 ++--
 storage/innobase/sync/sync0arr.c      |  4 ++--
 storage/innobase/sync/sync0rw.c       | 24 ++++++++++-----------
 storage/innobase/sync/sync0sync.c     |  4 ++--
 14 files changed, 78 insertions(+), 51 deletions(-)

diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index c1c497214db..06378462c53 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -389,8 +389,8 @@ static SHOW_VAR innodb_status_variables[]= {
   (char*) &export_vars.innodb_dblwr_pages_written,	  SHOW_LONG},
   {"dblwr_writes",
   (char*) &export_vars.innodb_dblwr_writes,		  SHOW_LONG},
-  {"have_atomic_builtins",
-  (char*) &export_vars.innodb_have_atomic_builtins,	  SHOW_BOOL},
+  {"have_sync_atomic",
+  (char*) &export_vars.innodb_have_sync_atomic,		  SHOW_BOOL},
   {"heap_enabled",
   (char*) &export_vars.innodb_heap_enabled,		  SHOW_BOOL},
   {"log_waits",
diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h
index 5533df4f608..28e67483fa6 100644
--- a/storage/innobase/include/os0sync.h
+++ b/storage/innobase/include/os0sync.h
@@ -12,6 +12,10 @@ Created 9/6/1995 Heikki Tuuri
 #include "univ.i"
 #include "ut0lst.h"
 
+#ifdef HAVE_SOLARIS_ATOMIC
+#include <atomic.h>
+#endif
+
 #ifdef __WIN__
 
 #define os_fast_mutex_t CRITICAL_SECTION
@@ -261,7 +265,7 @@ os_fast_mutex_free(
 /*===============*/
 	os_fast_mutex_t*	fast_mutex);	/* in: mutex to free */
 
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
+#ifdef UNIV_SYNC_ATOMIC
 /**************************************************************
 Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins. */
 UNIV_INLINE
@@ -272,6 +276,7 @@ os_compare_and_swap(
 	volatile lint*		ptr,		/* in: pointer to target */
 	lint			oldVal,		/* in: value to compare to */
 	lint			newVal);	/* in: value to swap in */
+
 /**************************************************************
 Atomic increment for InnoDB. Currently requires GCC atomic builtins. */
 UNIV_INLINE
@@ -282,7 +287,7 @@ os_atomic_increment(
 	volatile lint*		ptr,		/* in: pointer to target */
 	lint			amount);	/* in: amount of increment */
 
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
 
 #ifndef UNIV_NONINL
 #include "os0sync.ic"
diff --git a/storage/innobase/include/os0sync.ic b/storage/innobase/include/os0sync.ic
index 2a962529d95..4370e07e672 100644
--- a/storage/innobase/include/os0sync.ic
+++ b/storage/innobase/include/os0sync.ic
@@ -45,9 +45,10 @@ os_fast_mutex_trylock(
 #endif
 }
 
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
+#ifdef UNIV_SYNC_ATOMIC
 /**************************************************************
-Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins. */
+Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins
+or Solaris atomic_* functions. */
 UNIV_INLINE
 ibool
 os_compare_and_swap(
@@ -57,11 +58,15 @@ os_compare_and_swap(
 	lint		oldVal,		/* in: value to compare to */
 	lint		newVal)		/* in: value to swap in */
 {
-	if(__sync_bool_compare_and_swap(ptr, oldVal, newVal)) {
-		return(TRUE);
-	}
-
-	return(FALSE);
+#ifdef HAVE_GCC_ATOMIC_BULTINS
+	return (__sync_bool_compare_and_swap(ptr, oldVal, newVal));
+#elif HAVE_SOLARIS_ATOMIC
+	lint retVal = (lint)atomic_cas_ulong((volatile ulong_t *)ptr,
+		oldVal, newVal);
+	return (retVal == oldVal);
+#else
+#error "Need support for atomic ops"
+#endif
 }
 
 /**************************************************************
@@ -74,8 +79,13 @@ os_atomic_increment(
 	volatile lint*	ptr,		/* in: pointer to target */
 	lint		amount)		/* in: amount of increment */
 {
-	lint newVal = __sync_add_and_fetch(ptr, amount);
-	return newVal;
+#ifdef HAVE_GCC_ATOMIC_BULTINS
+	return (__sync_add_and_fetch(ptr, amount));
+#elif HAVE_SOLARIS_ATOMIC
+	return ((lint)atomic_add_long_nv((volatile ulong_t *)ptr, amount));
+#else
+#error "Need support for atomic ops"
+#endif
 }
 
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index c8a84ca390a..528c4053a2e 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -523,7 +523,7 @@ struct export_var_struct{
 	ulint innodb_buffer_pool_read_ahead_rnd;
 	ulint innodb_dblwr_pages_written;
 	ulint innodb_dblwr_writes;
-	ibool innodb_have_atomic_builtins;
+	ibool innodb_have_sync_atomic;
 	ibool innodb_heap_enabled;
 	ulint innodb_log_waits;
 	ulint innodb_log_write_requests;
diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h
index f329e7d161c..6de26535689 100644
--- a/storage/innobase/include/sync0rw.h
+++ b/storage/innobase/include/sync0rw.h
@@ -460,9 +460,9 @@ struct rw_lock_struct {
 	os_event_t	wait_ex_event;
 				/* Event for next-writer to wait on. A thread
 				must decrement lock_word before waiting. */
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 	mutex_t	mutex;		/* The mutex protecting rw_lock_struct */
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
 
 	UT_LIST_NODE_T(rw_lock_t) list;
 				/* All allocated rw locks are put into a
diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic
index bcadff0bd67..d5d3ee954be 100644
--- a/storage/innobase/include/sync0rw.ic
+++ b/storage/innobase/include/sync0rw.ic
@@ -103,7 +103,7 @@ rw_lock_get_reader_count(
 	return 0;
 }
 
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 UNIV_INLINE
 mutex_t*
 rw_lock_get_mutex(
@@ -146,7 +146,7 @@ rw_lock_lock_word_decr(
 	ulint		amount)	/* in: amount of decrement */
 {
 
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
+#ifdef UNIV_SYNC_ATOMIC
 
         lint local_lock_word = lock->lock_word;
 	while (local_lock_word > 0) {
@@ -159,7 +159,7 @@ rw_lock_lock_word_decr(
 	}
 	return(FALSE);
 
-#else /* HAVE_GCC_ATOMIC_BUILTINS */
+#else /* UNIV_SYNC_ATOMIC */
 
 	ibool success = FALSE;
 	mutex_enter(&(lock->mutex));
@@ -170,7 +170,7 @@ rw_lock_lock_word_decr(
 	mutex_exit(&(lock->mutex));
 	return success;
 
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
 
 }
 
@@ -186,11 +186,11 @@ rw_lock_lock_word_incr(
 	ulint		amount)	/* in: amount of increment */
 {
 
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
+#ifdef UNIV_SYNC_ATOMIC
 
 	return(os_atomic_increment(&(lock->lock_word), amount));
 
-#else /* HAVE_GCC_ATOMIC_BUILTINS */
+#else /* UNIV_SYNC_ATOMIC */
 
 	lint local_lock_word;
 
@@ -203,7 +203,7 @@ rw_lock_lock_word_incr(
 
         return local_lock_word;
 
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
 
 }
 
@@ -352,7 +352,7 @@ rw_lock_x_lock_func_nowait(
 
 	ibool success;
 
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
+#ifdef UNIV_SYNC_ATOMIC
 	success = os_compare_and_swap(&(lock->lock_word), X_LOCK_DECR, 0);
 #else
 
diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h
index cfc1c8d2c40..e311d75a189 100644
--- a/storage/innobase/include/sync0sync.h
+++ b/storage/innobase/include/sync0sync.h
@@ -16,6 +16,7 @@ Created 9/5/1995 Heikki Tuuri
 #include "os0thread.h"
 #include "os0sync.h"
 #include "sync0arr.h"
+#include "my_atomic.h"
 
 #ifndef UNIV_HOTBACKUP
 extern my_bool	timed_mutexes;
@@ -476,7 +477,10 @@ struct mutex_struct {
  				test-and-set instruction in Win32 and
  				x86 32/64 with GCC 4.1.0 or later version */
 #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+#elif defined(MY_ATOMIC_NOLOCK)
+				/* We have my_atomic_* routines that are
+				intrinsically atomic, so no need for the
+				mutex. */
 #else
 	os_fast_mutex_t
 		os_fast_mutex;	/* In other systems we use this OS mutex
diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic
index ffe8794eca5..f48077e43fe 100644
--- a/storage/innobase/include/sync0sync.ic
+++ b/storage/innobase/include/sync0sync.ic
@@ -88,8 +88,9 @@ mutex_test_and_set(
 		/* mutex_fence(); */
 
 		return(res);
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
-	return __sync_lock_test_and_set(&(mutex->lock_word), 1);
+#elif defined(MY_ATOMIC_NOLOCK)
+	return ((byte)my_atomic_swap8(
+		(int8 volatile *)&(mutex->lock_word), 1));
 #else
 	ibool	ret;
 
@@ -126,11 +127,11 @@ mutex_reset_lock_word(
 	__asm	MOV	EDX, 0
 		__asm	MOV	ECX, lw
 		__asm	XCHG	DL, BYTE PTR [ECX]
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+#elif defined(MY_ATOMIC_NOLOCK)
 	/* In theory __sync_lock_release should be used to release the lock.
 	Unfortunately, it does not work properly alone. The workaround is
 	that more conservative __sync_lock_test_and_set is used instead. */
-	__sync_lock_test_and_set(&(mutex->lock_word), 0);
+	(void)my_atomic_swap8((int8 volatile *)&(mutex->lock_word), 0);
 #else
 	mutex->lock_word = 0;
 
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index 6e9f3d74d22..ae6081185f7 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -123,6 +123,13 @@ by one. */
 /* Use malloc instead of innodb additional memory pool (great with tcmalloc) */
 #define UNIV_DISABLE_MEM_POOL
 
+#if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMIC)
+/*
+ * We have a full set of atomic ops available - we will use them
+ */
+#define UNIV_SYNC_ATOMIC
+#endif
+
 /*
 #define UNIV_SQL_DEBUG
 #define UNIV_LOG_DEBUG
diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
index 9ae821182bf..305be04874f 100644
--- a/storage/innobase/srv/srv0srv.c
+++ b/storage/innobase/srv/srv0srv.c
@@ -1900,10 +1900,10 @@ srv_export_innodb_status(void)
 	export_vars.innodb_buffer_pool_pages_misc = buf_pool->max_size
 		- UT_LIST_GET_LEN(buf_pool->LRU)
 		- UT_LIST_GET_LEN(buf_pool->free);
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
-	export_vars.innodb_have_atomic_builtins = 1;
+#ifdef UNIV_SYNC_ATOMIC
+	export_vars.innodb_have_sync_atomic = 1;
 #else
-	export_vars.innodb_have_atomic_builtins = 0;
+	export_vars.innodb_have_sync_atomic = 0;
 #endif
 #ifdef UNIV_DISABLE_MEM_POOL
 	export_vars.innodb_heap_enabled = 0;
diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c
index 41b0cd0fcd9..f64ebab1281 100644
--- a/storage/innobase/srv/srv0start.c
+++ b/storage/innobase/srv/srv0start.c
@@ -1068,9 +1068,9 @@ innobase_start_or_create_for_mysql(void)
 		"InnoDB: The InnoDB memory heap has been disabled.\n");
 #endif
 
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
+#ifdef UNIV_SYNC_ATOMIC
 	fprintf(stderr,
-		"InnoDB: Mutex and rw_lock use GCC atomic builtins.\n");
+		"InnoDB: Mutex and rw_lock use atomics.\n");
 #endif
 
 	/* Since InnoDB does not currently clean up all its internal data
diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c
index ee6e901ab81..5ee2a37bfd9 100644
--- a/storage/innobase/sync/sync0arr.c
+++ b/storage/innobase/sync/sync0arr.c
@@ -834,8 +834,8 @@ sync_array_object_signalled(
 /*========================*/
 	sync_array_t*	arr)	/* in: wait array */
 {
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
-	__sync_fetch_and_add(&(arr->sg_count),1);
+#ifdef UNIV_SYNC_ATOMIC
+	(void)os_atomic_increment((volatile lint *)&(arr->sg_count), 1);
 #else
 	sync_array_enter(arr);
 
diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c
index 0d6cb025260..ced2f72187a 100644
--- a/storage/innobase/sync/sync0rw.c
+++ b/storage/innobase/sync/sync0rw.c
@@ -195,7 +195,7 @@ rw_lock_create_func(
 	/* If this is the very first time a synchronization object is
 	created, then the following call initializes the sync system. */
 
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 	mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK);
 
 	lock->mutex.cfile_name = cfile_name;
@@ -206,7 +206,7 @@ rw_lock_create_func(
 	lock->mutex.mutex_type = 1;
 #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
 
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
 
 	lock->lock_word = X_LOCK_DECR;
 	rw_lock_set_waiters(lock, 0);
@@ -260,9 +260,9 @@ rw_lock_free(
 
 	lock->magic_n = 0;
 
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 	mutex_free(rw_lock_get_mutex(lock));
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
 
 	mutex_enter(&rw_lock_list_mutex);
 	os_event_free(lock->event);
@@ -413,13 +413,13 @@ rw_lock_x_lock_move_ownership(
 {
 	ut_ad(rw_lock_is_locked(lock, RW_LOCK_EX));
 
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
+#ifdef UNIV_SYNC_ATOMIC
         os_thread_id_t local_writer_thread = lock->writer_thread;
         os_thread_id_t new_writer_thread = os_thread_get_curr_id();
         while (TRUE) {
                 if ((int)local_writer_thread != -1) {
                         if(os_compare_and_swap(
-                               &(lock->writer_thread),
+                               (volatile lint*)&(lock->writer_thread),
                                local_writer_thread,
                                new_writer_thread)) {
                                 break;
@@ -428,12 +428,12 @@ rw_lock_x_lock_move_ownership(
                 local_writer_thread = lock->writer_thread;
         }
 	lock->pass = 0;
-#else /* HAVE_GCC_ATOMIC_BUILTINS */
+#else /* UNIV_SYNC_ATOMIC */
 	mutex_enter(&(lock->mutex));
 	lock->writer_thread = os_thread_get_curr_id();
 	lock->pass = 0;
 	mutex_exit(&(lock->mutex));
-#endif /* HAVE_GCC_ATOMIC_BUILTINS */
+#endif /* UNIV_SYNC_ATOMIC */
 }
 
 /**********************************************************************
@@ -883,7 +883,7 @@ rw_lock_list_print_info(
 
 		count++;
 
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 		mutex_enter(&(lock->mutex));
 #endif
 		if (lock->lock_word != X_LOCK_DECR) {
@@ -902,7 +902,7 @@ rw_lock_list_print_info(
 				info = UT_LIST_GET_NEXT(list, info);
 			}
 		}
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 		mutex_exit(&(lock->mutex));
 #endif
 
@@ -928,7 +928,7 @@ rw_lock_print(
 		"RW-LATCH INFO\n"
 		"RW-LATCH: %p ", (void*) lock);
 
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 	mutex_enter(&(lock->mutex));
 #endif
 	if (lock->lock_word != X_LOCK_DECR) {
@@ -945,7 +945,7 @@ rw_lock_print(
 			info = UT_LIST_GET_NEXT(list, info);
 		}
 	}
-#ifndef HAVE_GCC_ATOMIC_BUILTINS
+#ifndef UNIV_SYNC_ATOMIC
 	mutex_exit(&(lock->mutex));
 #endif
 }
diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c
index 4176143d679..a8b1ac4926e 100644
--- a/storage/innobase/sync/sync0sync.c
+++ b/storage/innobase/sync/sync0sync.c
@@ -238,7 +238,7 @@ mutex_create_func(
 {
 #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
 	mutex_reset_lock_word(mutex);
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+#elif defined(MY_ATOMIC_NOLOCK)
 	mutex_reset_lock_word(mutex);
 #else
 	os_fast_mutex_init(&(mutex->os_fast_mutex));
@@ -331,7 +331,7 @@ mutex_free(
 	os_event_free(mutex->event);
 
 #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+#elif defined(MY_ATOMIC_NOLOCK)
 #else
 	os_fast_mutex_free(&(mutex->os_fast_mutex));
 #endif
-- 
2.30.9