From cee09a02614acf00de1a711287c25fdf26e0e4ad Mon Sep 17 00:00:00 2001
From: Vasily Titskiy <Vasiliy.Titskiy@bioscrypt.com>
Date: Thu, 26 May 2011 13:27:25 -0400
Subject: [PATCH] Add support for GCC 3.x (no _sync* atomic builtins)

Use atomic routines from libstdc++ instead.
---
 cpp/configure.in       |  4 +---
 cpp/src/Makefile.am    |  3 ++-
 cpp/src/gcc_atomic.cpp | 17 +++++++++++++++++
 cpp/src/gcc_atomic.h   | 33 +++++++++++++++++++++++++++++++++
 msgpack/sysdep.h       |  4 ++--
 5 files changed, 55 insertions(+), 6 deletions(-)
 create mode 100644 cpp/src/gcc_atomic.cpp
 create mode 100644 cpp/src/gcc_atomic.h

diff --git a/cpp/configure.in b/cpp/configure.in
index 95635c3c..cc86cdfd 100644
--- a/cpp/configure.in
+++ b/cpp/configure.in
@@ -50,9 +50,7 @@ AC_CACHE_CHECK([for __sync_* atomic operations], msgpack_cv_atomic_ops, [
 	], [], msgpack_cv_atomic_ops="yes")
 	])
 if test "$msgpack_cv_atomic_ops" != "yes"; then
-	AC_MSG_ERROR([__sync_* atomic operations are not supported.
-
-Note that gcc < 4.1 is not supported.
+	AC_MSG_NOTICE([__sync_* atomic operations are not found. Use libstdc++ instead.
 
 If you are using gcc >= 4.1 and the default target CPU architecture is "i386", try to
 add CFLAGS="-march=i686" and CXXFLAGS="-march=i686" options to ./configure as follows:
diff --git a/cpp/src/Makefile.am b/cpp/src/Makefile.am
index 0979d235..d96217a5 100644
--- a/cpp/src/Makefile.am
+++ b/cpp/src/Makefile.am
@@ -10,7 +10,8 @@ libmsgpack_la_SOURCES = \
 
 if ENABLE_CXX
 libmsgpack_la_SOURCES += \
-		object.cpp
+		object.cpp \
+		gcc_atomic.cpp
 endif
 
 # -version-info CURRENT:REVISION:AGE
diff --git a/cpp/src/gcc_atomic.cpp b/cpp/src/gcc_atomic.cpp
new file mode 100644
index 00000000..599e832b
--- /dev/null
+++ b/cpp/src/gcc_atomic.cpp
@@ -0,0 +1,17 @@
+#if defined(__GNUC__) && ((__GNUC__*10 + __GNUC_MINOR__) < 41)
+
+#include "gcc_atomic.h"
+#include <bits/atomicity.h>
+
+int _msgpack_sync_decr_and_fetch(volatile _msgpack_atomic_counter_t* ptr)
+{
+	return  __gnu_cxx::__exchange_and_add(ptr, -1);
+}
+
+int _msgpack_sync_incr_and_fetch(volatile _msgpack_atomic_counter_t* ptr)
+{
+	return  __gnu_cxx::__exchange_and_add(ptr, 1);
+}
+
+
+#endif // old gcc workaround
diff --git a/cpp/src/gcc_atomic.h b/cpp/src/gcc_atomic.h
new file mode 100644
index 00000000..842a48fb
--- /dev/null
+++ b/cpp/src/gcc_atomic.h
@@ -0,0 +1,33 @@
+/*
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#ifndef MSGPACK_GCC_ATOMIC_H__
+#define MSGPACK_GCC_ATOMIC_H__
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef int _msgpack_atomic_counter_t;
+
+int _msgpack_sync_decr_and_fetch(volatile _msgpack_atomic_counter_t* ptr);
+int _msgpack_sync_incr_and_fetch(volatile _msgpack_atomic_counter_t* ptr);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#endif // MSGPACK_GCC_ATOMIC_H__
diff --git a/msgpack/sysdep.h b/msgpack/sysdep.h
index 557c7cd6..1707e900 100644
--- a/msgpack/sysdep.h
+++ b/msgpack/sysdep.h
@@ -36,19 +36,19 @@ typedef unsigned __int64 uint64_t;
 #include <stdbool.h>
 #endif
 
-
 #ifdef _WIN32
 #define _msgpack_atomic_counter_header <windows.h>
 typedef long _msgpack_atomic_counter_t;
 #define _msgpack_sync_decr_and_fetch(ptr) InterlockedDecrement(ptr)
 #define _msgpack_sync_incr_and_fetch(ptr) InterlockedIncrement(ptr)
+#elif defined(__GNUC__) && ((__GNUC__*10 + __GNUC_MINOR__) < 41)
+#define _msgpack_atomic_counter_header "gcc_atomic.h"
 #else
 typedef unsigned int _msgpack_atomic_counter_t;
 #define _msgpack_sync_decr_and_fetch(ptr) __sync_sub_and_fetch(ptr, 1)
 #define _msgpack_sync_incr_and_fetch(ptr) __sync_add_and_fetch(ptr, 1)
 #endif
 
-
 #ifdef _WIN32
 
 #ifdef __cplusplus