]> granicus.if.org Git - gc/commitdiff
Put variable/function declarations into extern 'C' in headers
authorJay Krell <jaykrell@microsoft.com>
Wed, 7 Feb 2018 22:36:49 +0000 (01:36 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Wed, 7 Feb 2018 22:36:49 +0000 (01:36 +0300)
Issue #201 (bdwgc).

Extern "C" should be only around declarations, not includes.
In particular, do not include 3rd-party headers (as well as our own
files as they could include others).

* include/gc.h [GC_PTHREADS]: Do not wrap include gc_pthread_redirects.h
into extern "C" block.
* include/gc_disclaim.h: Wrap variable and function declarations (but
not included headers).
* include/gc_inline.h: Likewise.
* include/gc_pthread_redirects.h [!GC_PTHREAD_REDIRECTS_ONLY]: Likewise.
* include/private/darwin_semaphore.h: Likewise.
* include/private/darwin_stop_world.h: Likewise.
* include/private/dbg_mlc.h: Likewise.
* include/private/gc_atomic_ops.h [GC_BUILTIN_ATOMIC]: Likewise.
* include/private/gc_hdrs.h: Likewise.
* include/private/gc_locks.h [THREADS]: Likewise.
* include/private/gc_pmark.h: Likewise.
* include/private/gc_priv.h: Likewise.
* include/private/gcconfig.h: Likewise.
* include/private/pthread_stop_world.h: Likewise.
* include/private/pthread_support.h [GC_PTHREADS && !GC_WIN32_THREADS]:
Likewise.
* include/private/specific.h: Likewise.
* include/private/thread_local_alloc.h [THREAD_LOCAL_ALLOC]: Likewise.

17 files changed:
include/gc.h
include/gc_disclaim.h
include/gc_inline.h
include/gc_pthread_redirects.h
include/private/darwin_semaphore.h
include/private/darwin_stop_world.h
include/private/dbg_mlc.h
include/private/gc_atomic_ops.h
include/private/gc_hdrs.h
include/private/gc_locks.h
include/private/gc_pmark.h
include/private/gc_priv.h
include/private/gcconfig.h
include/private/pthread_stop_world.h
include/private/pthread_support.h
include/private/specific.h
include/private/thread_local_alloc.h

index f206cf8cb492b70d5bafb8de155a902205574859..e1f8fa7b907a7625a8d3c967dc8713e26e34924e 100644 (file)
@@ -1620,7 +1620,13 @@ GC_API void (GC_CALLBACK * GC_is_visible_print_proc)(void *);
 #ifdef GC_PTHREADS
   /* For pthread support, we generally need to intercept a number of    */
   /* thread library calls.  We do that here by macro defining them.     */
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
 # include "gc_pthread_redirects.h"
+# ifdef __cplusplus
+    extern "C" {
+# endif
 #endif
 
 /* This returns a list of objects, linked through their first word.     */
@@ -2003,7 +2009,7 @@ GC_API void GC_CALL GC_win32_free_heap(void);
 #endif /* _AMIGA && !GC_AMIGA_MAKINGLIB */
 
 #ifdef __cplusplus
-  }  /* end of extern "C" */
+  } /* extern "C" */
 #endif
 
 #endif /* GC_H */
index 716b741f60ebd56ce85cffe690f164698419740c..b7209772385a6c6dbab1392872b91901f5cc6663 100644 (file)
 
 #include "gc.h"
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* This API is defined only if the library has been suitably compiled   */
 /* (i.e. with ENABLE_DISCLAIM defined).                                 */
 
@@ -55,4 +59,8 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
         GC_finalized_malloc(size_t /*size*/,
                             const struct GC_finalizer_closure * /*fc*/);
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif
index 45281c9db580a3434b1795cea44c4fcc09a42c65..956bf46525393e8954ce2b5ee4c3c159da70adab 100644 (file)
 # endif
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 #ifndef GC_PREFETCH_FOR_WRITE
 # if GC_GNUC_PREREQ(3, 0) && !defined(GC_NO_PREFETCH_FOR_WRITE)
 #   define GC_PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
@@ -182,4 +186,8 @@ GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
 GC_API void GC_CALL GC_print_free_list(int /* kind */,
                                        size_t /* sz_in_granules */);
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif /* !GC_INLINE_H */
index 8dcf7ebf6a5221855426f5d177e38dba556716a7..92951c3c66019886798652dba478d682910e65f9 100644 (file)
 /* to thread specific data on the thread stack.                         */
 
 #ifndef GC_PTHREAD_REDIRECTS_ONLY
+
 # include <pthread.h>
+# ifndef GC_NO_DLOPEN
+#   include <dlfcn.h>
+# endif
+# ifndef GC_NO_PTHREAD_SIGMASK
+#   include <signal.h>  /* needed anyway for proper redirection */
+# endif
+
+# ifdef __cplusplus
+    extern "C" {
+# endif
 
 # ifndef GC_SUSPEND_THREAD_ID
 #   define GC_SUSPEND_THREAD_ID pthread_t
 # endif
 
 # ifndef GC_NO_DLOPEN
-#   include <dlfcn.h>
     GC_API void *GC_dlopen(const char * /* path */, int /* mode */);
 # endif /* !GC_NO_DLOPEN */
 
 # ifndef GC_NO_PTHREAD_SIGMASK
-#   include <signal.h>  /* needed anyway for proper redirection */
 #   if defined(GC_PTHREAD_SIGMASK_NEEDED) \
         || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) \
         || (_POSIX_C_SOURCE >= 199506L) || (_XOPEN_SOURCE >= 500)
 #   define GC_PTHREAD_EXIT_DECLARED
     GC_API void GC_pthread_exit(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
 # endif
+
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
+
 #endif /* !GC_PTHREAD_REDIRECTS_ONLY */
 
 #if !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP)
index 62f185d64561726d42181f259279a02128cde221..22cbb8f28a8547b1e349914f3ed565e0d6c34bb5 100644 (file)
 # error darwin_semaphore.h included with GC_DARWIN_THREADS not defined
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* This is a very simple semaphore implementation for Darwin.  It is    */
 /* implemented in terms of pthread calls so it is not async signal      */
 /* safe.  But this is not a problem because signals are not used to     */
@@ -77,4 +81,8 @@ GC_INLINE int sem_destroy(sem_t *sem) {
            || pthread_mutex_destroy(&sem->mutex) != 0 ? -1 : 0;
 }
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif
index 399304ead07950d935aca25c2d27ae47115d7192..8f69d9d085feb8f3fce218187dfa699f11670657 100644 (file)
 #include <mach/mach.h>
 #include <mach/thread_act.h>
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 struct thread_stop_info {
   mach_port_t mach_thread;
   ptr_t stack_ptr; /* Valid only when thread is in a "blocked" state.   */
@@ -43,4 +47,8 @@ struct thread_stop_info {
   GC_INNER GC_bool GC_is_mach_marker(thread_act_t);
 #endif
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif
index ae2c70e9d26bf5951ce08bc87f23a7a280af74f6..2ba8f9cb852f6e07c561a02516d610434962dac4 100644 (file)
 # include "gc_backptr.h"
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 #if CPP_WORDSZ == 32
 # define START_FLAG (word)0xfedcedcb
 # define END_FLAG (word)0xbcdecdef
@@ -167,4 +171,8 @@ typedef struct {
 # define GC_HAS_DEBUG_INFO(p) (GC_has_other_debug_info(p) > 0)
 #endif
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif /* _DBG_MLC_H */
index 1b9a47125e5e5b6db4d60b66594e0bb852df34f0..3bdf5647800619496b59741cc82e7e99753ba9fb 100644 (file)
 #ifdef GC_BUILTIN_ATOMIC
 
 # include "gc.h" /* for GC_word */
+
+# ifdef __cplusplus
+    extern "C" {
+# endif
+
   typedef GC_word AO_t;
 
 # ifdef GC_PRIVATE_H /* have GC_INLINE */
 #   define AO_HAVE_compare_and_swap_release
 # endif
 
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
+
 #else
   /* Fallback to libatomic_ops. */
 # include "atomic_ops.h"
index a7892a31f92641aea201d22cfe7b0fa78a80f475..b71ae3e9843e110a4ba658beec27abfd7e4f3e1b 100644 (file)
 #ifndef GC_HEADERS_H
 #define GC_HEADERS_H
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 typedef struct hblkhdr hdr;
 
 #if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
@@ -208,4 +212,8 @@ typedef struct bi {
 /* h.  Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr).             */
 #define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (size_t)(hhdr))
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif /* GC_HEADERS_H */
index 82bb252228eb835ac83102b568d92d18c31609f9..5657606ab76fec4d18abdfe7eaf0068755bf6309 100644 (file)
 #  ifdef PCR
 #    include <base/PCR_Base.h>
 #    include <th/PCR_Th.h>
+#  endif
+
+#  ifdef __cplusplus
+     extern "C" {
+#  endif
+
+#  ifdef PCR
      GC_EXTERN PCR_Th_ML GC_allocate_ml;
 #    if defined(CPPCHECK)
 #      define DCL_LOCK_STATE /* empty */
 #  endif
 
 #  if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
+#    ifdef __cplusplus
+       } /* extern "C" */
+#    endif
 #    ifndef WIN32_LEAN_AND_MEAN
 #      define WIN32_LEAN_AND_MEAN 1
 #    endif
 #    define NOSERVICE
 #    include <windows.h>
+#    ifdef __cplusplus
+       extern "C" {
+#    endif
 #    define NO_THREAD (DWORD)(-1)
      GC_EXTERN CRITICAL_SECTION GC_allocate_ml;
 #    ifdef GC_ASSERTIONS
 #      define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml)
 #    endif /* !GC_ASSERTIONS */
 #  elif defined(GC_PTHREADS)
+#    ifdef __cplusplus
+       } /* extern "C" */
+#    endif
 #    include <pthread.h>
-
+#    ifdef __cplusplus
+       extern "C" {
+#    endif
      /* Posix allows pthread_t to be a struct, though it rarely is.     */
      /* Unfortunately, we need to use a pthread_t to index a data       */
      /* structure.  It also helps if comparisons don't involve a        */
                 /* != NUMERIC_THREAD_ID(pthread_self()) for any thread */
 
 #    ifdef SN_TARGET_PSP2
+#      ifdef __cplusplus
+         } /* extern "C" */
+#      endif
 #      include "psp2-support.h"
+#      ifdef __cplusplus
+         extern "C" {
+#      endif
        GC_EXTERN WapiMutex GC_allocate_ml_PSP2;
 #      define UNCOND_LOCK() { int res; GC_ASSERT(I_DONT_HOLD_LOCK()); \
                               res = PSP2_MutexLock(&GC_allocate_ml_PSP2); \
 #      endif
 #    endif /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
 #    ifdef USE_PTHREAD_LOCKS
+#      ifdef __cplusplus
+         } /* extern "C" */
+#      endif
 #      include <pthread.h>
+#      ifdef __cplusplus
+         extern "C" {
+#      endif
        GC_EXTERN pthread_mutex_t GC_allocate_ml;
 #      ifdef GC_ASSERTIONS
 #        define UNCOND_LOCK() { GC_ASSERT(I_DONT_HOLD_LOCK()); \
 #    endif
 #  endif
 
+#  ifdef __cplusplus
+     } /* extern "C" */
+#  endif
+
 # else /* !THREADS */
 #   define LOCK() (void)0
 #   define UNLOCK() (void)0
index ec0ebc9fcd37192da93ec24f82caf33cb561b52e..280cffece1b11a7d277cf0df7829dae1338a6143 100644 (file)
 # include "gc_priv.h"
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* The real declarations of the following is in gc_priv.h, so that      */
 /* we can avoid scanning the following table.                           */
 /*
@@ -478,4 +482,8 @@ typedef int mark_state_t;       /* Current state of marking, as follows:*/
 
 GC_EXTERN mark_state_t GC_mark_state;
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif  /* GC_PMARK_H */
index b82b8a96d61a6855d6c619e386f32cf95fba0ad7..7efc8bf9257f051094dfc63dd1d298f2d331cc5a 100644 (file)
@@ -313,6 +313,10 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
                     /* This is now really controlled at startup,        */
                     /* through GC_all_interior_pointers.                */
 
+/* Note: never put extern "C" around an #include.                       */
+#ifdef __cplusplus
+  extern "C" {
+#endif
 
 #ifndef GC_NO_FINALIZATION
 # define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
@@ -403,6 +407,9 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
   GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
 #endif
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
 
 /*********************************/
 /*                               */
@@ -440,8 +447,14 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
 # define MS_TIME_DIFF(a,b) ((long)((a)-(b)))
 #elif defined(NN_PLATFORM_CTR)
 # define CLOCK_TYPE long long
+# ifdef __cplusplus
+    extern "C" {
+# endif
   CLOCK_TYPE n3ds_get_system_tick(void);
   CLOCK_TYPE n3ds_convert_tick_to_ms(CLOCK_TYPE tick);
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
 # define GET_TIME(x) (void)(x = n3ds_get_system_tick())
 # define MS_TIME_DIFF(a,b) ((long)n3ds_convert_tick_to_ms((a)-(b)))
 #else /* !BSD_TIME && !NN_PLATFORM_CTR && !MSWIN32 && !MSWINCE */
@@ -495,11 +508,18 @@ typedef char * ptr_t;   /* A generic pointer to which we can add        */
 #   define BZERO(x,n) bzero((void *)(x),(size_t)(n))
 # endif
 
+#ifdef PCR
+# include "th/PCR_ThCtl.h"
+#endif
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /*
  * Stop and restart mutator threads.
  */
 # ifdef PCR
-#     include "th/PCR_ThCtl.h"
 #     define STOP_WORLD() \
         PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal, \
                                    PCR_allSigsBlocked, \
@@ -638,6 +658,10 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
 # define GETENV(name) getenv(name)
 #endif
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #if defined(DARWIN)
 # include <mach/thread_status.h>
 # ifndef MAC_OS_X_VERSION_MAX_ALLOWED
@@ -719,6 +743,25 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
 # endif
 #endif /* DARWIN */
 
+#ifdef PARALLEL_MARK
+# include "gc_atomic_ops.h"
+# define counter_t volatile AO_t
+#else
+  typedef size_t counter_t;
+# if defined(THREADS) && (defined(MPROTECT_VDB) || defined(THREAD_SANITIZER) \
+                || (defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)))
+#   include "gc_atomic_ops.h"
+# endif
+#endif /* !PARALLEL_MARK */
+
+#include "../gc_tiny_fl.h"
+
+#include <setjmp.h>
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /*********************************/
 /*                               */
 /* Word-size-dependent defines   */
@@ -750,7 +793,7 @@ GC_EXTERN GC_warn_proc GC_current_warn_proc;
 /* separate free lists for each multiple of GRANULE_BYTES       */
 /* up to (TINY_FREELISTS-1) * GRANULE_BYTES.  After that they   */
 /* may be spread out further.                                   */
-#include "../gc_tiny_fl.h"
+
 #define GRANULE_BYTES GC_GRANULE_BYTES
 #define TINY_FREELISTS GC_TINY_FREELISTS
 
@@ -966,17 +1009,6 @@ typedef word page_hash_table[PHT_SIZE];
            /* initial group of mark bits, and it is safe     */
            /* to allocate smaller header for large objects.  */
 
-#ifdef PARALLEL_MARK
-# include "gc_atomic_ops.h"
-# define counter_t volatile AO_t
-#else
-  typedef size_t counter_t;
-# if defined(THREADS) && (defined(MPROTECT_VDB) || defined(THREAD_SANITIZER) \
-                || (defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)))
-#   include "gc_atomic_ops.h"
-# endif
-#endif /* !PARALLEL_MARK */
-
 union word_ptr_ao_u {
   word w;
   signed_word sw;
@@ -2216,14 +2248,8 @@ GC_API_PRIV void GC_err_printf(const char * format, ...)
 
 /* Basic logging routine.  Typically, GC_log_printf is called directly  */
 /* only inside various DEBUG_x blocks.                                  */
-#if defined(__cplusplus) && defined(SYMBIAN)
-  extern "C" {
-#endif
 GC_API_PRIV void GC_log_printf(const char * format, ...)
                         GC_ATTR_FORMAT_PRINTF(1, 2);
-#if defined(__cplusplus) && defined(SYMBIAN)
-  }
-#endif
 
 #ifndef GC_ANDROID_LOG
 # define GC_PRINT_STATS_FLAG (GC_print_stats != 0)
@@ -2549,8 +2575,6 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
 # define GC_SEM_INIT_PSHARED 0
 #endif
 
-#include <setjmp.h>
-
 /* Some macros for setjmp that works across signal handlers     */
 /* were possible, and a couple of routines to facilitate        */
 /* catching accesses to bad addresses when that's               */
@@ -2558,7 +2582,13 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
 #if (defined(UNIX_LIKE) || (defined(NEED_FIND_LIMIT) && defined(CYGWIN32))) \
     && !defined(GC_NO_SIGSETJMP)
 # if defined(SUNOS5SIGS) && !defined(FREEBSD) && !defined(LINUX)
-#  include <sys/siginfo.h>
+#   ifdef __cplusplus
+      } /* extern "C" */
+#   endif
+#   include <sys/siginfo.h>
+#   ifdef __cplusplus
+      extern "C" {
+#   endif
 # endif
   /* Define SETJMP and friends to be the version that restores  */
   /* the signal mask.                                           */
@@ -2591,7 +2621,13 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
 #endif
 
 #if defined(DATASTART_USES_BSDGETDATASTART)
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
 # include <machine/trap.h>
+# ifdef __cplusplus
+    extern "C" {
+# endif
 # if !defined(PCR)
 #   define NEED_FIND_LIMIT
 # endif
@@ -2650,4 +2686,8 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str,
 # define ASSERT_CANCEL_DISABLED() (void)0
 #endif /* !CANCEL_SAFE */
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif /* GC_PRIVATE_H */
index c4c69a3d543e35bbc236c4fd7ddb56a7e0a769c8..a8e55dd298e83685187b4f09e55a1d592f16608b 100644 (file)
 #   include <stddef.h>  /* For size_t etc. */
 # endif
 
+/* Note: Only wrap our own declarations, and not the included headers.  */
+/* In this case, wrap our entire file, but temporarily unwrap/rewrap    */
+/* around #includes.  Types and macros do not need such wrapping, only  */
+/* the declared global data and functions.                              */
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* Convenient internal macro to test version of Clang.  */
 #if defined(__clang__) && defined(__clang_major__)
 # define GC_CLANG_PREREQ(major, minor) \
 /* And one for Darwin: */
 # if defined(macosx) || (defined(__APPLE__) && defined(__MACH__))
 #   define DARWIN
+#   ifdef __cplusplus
+      } /* extern "C" */
+#   endif
 #   include <TargetConditionals.h>
+#   ifdef __cplusplus
+      extern "C" {
+#   endif
 # endif
 
 /* Determine the machine type: */
 #   error IBM PC/RT no longer supported.
 # endif
 # if (defined(sun) || defined(__sun)) && (defined(sparc) || defined(__sparc))
-#   define SPARC
-    /* Test for SunOS 5.x */
+            /* Test for SunOS 5.x */
+#   ifdef __cplusplus
+      } /* extern "C" */
+#   endif
 #   include <errno.h>
+#   ifdef __cplusplus
+      extern "C" {
+#   endif
+#   define SPARC
 #   define SOLARIS
 #   define mach_type_known
 # elif defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
 #       define LINUX_STACKBOTTOM
 #       define MPROTECT_VDB
 #       ifdef __ELF__
-#            define DYNAMIC_LOADING
-#            include <features.h>
-#            if defined(__GLIBC__) && __GLIBC__ >= 2
-#              define SEARCH_FOR_DATA_START
-#            else /* !GLIBC2 */
-               extern char **__environ;
-#              define DATASTART ((ptr_t)(&__environ))
+#         define DYNAMIC_LOADING
+#         ifdef __cplusplus
+            } /* extern "C" */
+#         endif
+#         include <features.h>
+#         ifdef __cplusplus
+            extern "C" {
+#         endif
+#         if defined(__GLIBC__) && __GLIBC__ >= 2
+#           define SEARCH_FOR_DATA_START
+#         else /* !GLIBC2 */
+            extern char **__environ;
+#           define DATASTART ((ptr_t)(&__environ))
                              /* hideous kludge: __environ is the first */
                              /* word in crt0.o, and delimits the start */
                              /* of the data segment, no matter which   */
                              /* would include .rodata, which may       */
                              /* contain large read-only data tables    */
                              /* that we'd rather not scan.             */
-#            endif /* !GLIBC2 */
-             extern int _end[];
-#            define DATAEND ((ptr_t)(_end))
+#         endif /* !GLIBC2 */
+          extern int _end[];
+#         define DATAEND ((ptr_t)(_end))
 #       else
-             extern int etext[];
-#            define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
+          extern int etext[];
+#         define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
 #       endif
 #   endif
 #   ifdef AMIGA
 #   endif
 #   ifdef MACOS
 #     ifndef __LOWMEM__
-#     include <LowMem.h>
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
+#       include <LowMem.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #     endif
 #     define OS_TYPE "MACOS"
                 /* see os_dep.c for details of global data segments. */
 #   ifdef MACOS
 #     define ALIGNMENT 2  /* Still necessary?  Could it be 4?   */
 #     ifndef __LOWMEM__
-#     include <LowMem.h>
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
+#       include <LowMem.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #     endif
 #     define OS_TYPE "MACOS"
                         /* see os_dep.c for details of global data segments. */
 #     define DATAEND   ((ptr_t)get_end())
 #     define USE_MMAP_ANON
 #     define MPROTECT_VDB
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <unistd.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)getpagesize()
 #     if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
         /* The performance impact of prefetches is untested */
 #     define OS_TYPE "OPENBSD"
 #     define ALIGNMENT 4
 #     ifndef GC_OPENBSD_THREADS
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/param.h>
 #       include <uvm/uvm_extern.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
         /* USRSTACK is defined in <machine/vmparam.h> but that is       */
         /* protected by _KERNEL in <uvm/uvm_param.h> file.              */
 #       ifdef USRSTACK
 #         define HEAP_START DATAEND
 #       endif
 #       define PROC_VDB
-/*      HEURISTIC1 reportedly no longer works under 2.7.                */
-/*      HEURISTIC2 probably works, but this appears to be preferable.   */
-/*      Apparently USRSTACK is defined to be USERLIMIT, but in some     */
-/*      installations that's undefined.  We work around this with a     */
-/*      gross hack:                                                     */
+        /* HEURISTIC1 reportedly no longer works under 2.7.             */
+        /* HEURISTIC2 probably works, but this appears to be preferable.*/
+        /* Apparently USRSTACK is defined to be USERLIMIT, but in some  */
+        /* installations that's undefined.  We work around this with a  */
+        /* gross hack:                                                  */
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/vmparam.h>
+#       include <unistd.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USERLIMIT
           /* This should work everywhere, but doesn't.  */
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       else
 #         define HEURISTIC2
 #       endif
-#       include <unistd.h>
 #       define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE)
                 /* getpagesize() appeared to be missing from at least one */
                 /* Solaris 5.4 installation.  Weird.                      */
 #   ifdef OPENBSD
 #     define OS_TYPE "OPENBSD"
 #     ifndef GC_OPENBSD_THREADS
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/param.h>
 #       include <uvm/uvm_extern.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USRSTACK
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       else
 #   endif
 #   ifdef HAIKU
 #     define OS_TYPE "HAIKU"
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <OS.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)B_PAGE_SIZE
       extern int etext[];
 #     define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
 #       define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext)
 #       define DATASTART_IS_FUNC
 #       define DATAEND ((ptr_t)(_end))
-/*      # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7,      */
-/*      but reportedly breaks under 2.8.  It appears that the stack     */
-/*      base is a property of the executable, so this should not break  */
-/*      old executables.                                                */
-/*      HEURISTIC2 probably works, but this appears to be preferable.   */
-/*      Apparently USRSTACK is defined to be USERLIMIT, but in some     */
-/*      installations that's undefined.  We work around this with a     */
-/*      gross hack:                                                     */
+        /* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7,   */
+        /* but reportedly breaks under 2.8.  It appears that the stack  */
+        /* base is a property of the executable, so this should not     */
+        /* break old executables.                                       */
+        /* HEURISTIC2 probably works, but this appears to be preferable.*/
+        /* Apparently USRSTACK is defined to be USERLIMIT, but in some  */
+        /* installations that's undefined.  We work around this with a  */
+        /* gross hack:                                                  */
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/vmparam.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USERLIMIT
           /* This should work everywhere, but doesn't.  */
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       define DATAEND ((ptr_t)(&_end))
 #       define STACK_GROWS_DOWN
 #       define HEURISTIC2
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <unistd.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE)
 #       define DYNAMIC_LOADING
 #       ifndef USE_MMAP
                 /* This encourages mmap to give us low addresses,       */
                 /* thus allowing the heap to grow to ~3GB               */
 #       ifdef __ELF__
-#            define DYNAMIC_LOADING
-#            include <features.h>
+#           define DYNAMIC_LOADING
+#           ifdef __cplusplus
+              } /* extern "C" */
+#           endif
+#           include <features.h>
+#           ifdef __cplusplus
+              extern "C" {
+#           endif
 #            if defined(__GLIBC__) && __GLIBC__ >= 2 \
                 || defined(HOST_ANDROID) || defined(HOST_TIZEN)
 #                define SEARCH_FOR_DATA_START
 #       if defined(__GLIBC__) && !defined(__UCLIBC__)
           /* Workaround lock elision implementation for some glibc.     */
 #         define GLIBC_2_19_TSX_BUG
+#         ifdef __cplusplus
+            } /* extern "C" */
+#         endif
 #         include <gnu/libc-version.h> /* for gnu_get_libc_version() */
+#         ifdef __cplusplus
+            extern "C" {
+#         endif
 #       endif
 #   endif
 #   ifdef CYGWIN32
 #   endif
 #   ifdef DJGPP
 #       define OS_TYPE "DJGPP"
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include "stubinfo.h"
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
         extern int etext[];
         extern int _stklen;
         extern int __djgpp_stack_limit;
 #   ifdef OPENBSD
 #       define OS_TYPE "OPENBSD"
 #       ifndef GC_OPENBSD_THREADS
+#         ifdef __cplusplus
+            } /* extern "C" */
+#         endif
 #         include <sys/param.h>
 #         include <uvm/uvm_extern.h>
+#         ifdef __cplusplus
+            extern "C" {
+#         endif
 #         ifdef USRSTACK
 #           define STACKBOTTOM ((ptr_t)USRSTACK)
 #         else
 #   endif
 #   ifdef RTEMS
 #       define OS_TYPE "RTEMS"
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/unistd.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
         extern int etext[];
         extern int end[];
         void *rtems_get_stack_bottom(void);
 #     define STACKBOTTOM ((ptr_t)0xc0000000)
 #     define USE_MMAP_ANON
 #     define MPROTECT_VDB
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <unistd.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)getpagesize()
       /* There seems to be some issues with trylock hanging on darwin.  */
       /* This should be looked into some more.                          */
 #     define OS_TYPE "OPENBSD"
 #     define ALIGNMENT 4
 #     ifndef GC_OPENBSD_THREADS
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/param.h>
 #       include <uvm/uvm_extern.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USRSTACK
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       else
 #       define STACKBOTTOM ((ptr_t)environ)
 #     endif
 #     define DYNAMIC_LOADING
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <unistd.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)sysconf(_SC_PAGE_SIZE)
 #     ifndef __GNUC__
 #       define PREFETCH(x)  do { \
 #  ifdef OPENBSD
 #     define OS_TYPE "OPENBSD"
 #     ifndef GC_OPENBSD_THREADS
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/param.h>
 #       include <uvm/uvm_extern.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USRSTACK
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       else
 #       define OS_TYPE "OPENBSD"
 #       define ELF_CLASS ELFCLASS64
 #       ifndef GC_OPENBSD_THREADS
+#         ifdef __cplusplus
+            } /* extern "C" */
+#         endif
 #         include <sys/param.h>
 #         include <uvm/uvm_extern.h>
+#         ifdef __cplusplus
+            extern "C" {
+#         endif
 #         ifdef USRSTACK
 #           define STACKBOTTOM ((ptr_t)USRSTACK)
 #         else
 #       define STACKBOTTOM ((ptr_t)environ)
 #       define HPUX_STACKBOTTOM
 #       define DYNAMIC_LOADING
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <unistd.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       define GETPAGESIZE() (unsigned)sysconf(_SC_PAGE_SIZE)
         /* The following was empirically determined, and is probably    */
         /* not very robust.                                             */
 #           define CLEAR_DOUBLE(x) \
               __asm__ ("        stf.spill       [%0]=f0": : "r"((void *)(x)))
 #         else
+#           ifdef __cplusplus
+              } /* extern "C" */
+#           endif
 #           include <ia64intrin.h>
+#           ifdef __cplusplus
+              extern "C" {
+#           endif
 #           define PREFETCH(x) __lfetch(__lfhint_none, (x))
 #           define GC_PREFETCH_FOR_WRITE(x) __lfetch(__lfhint_nta, (x))
 #           define CLEAR_DOUBLE(x) __stf_spill((void *)(x), 0)
 #     define STACKBOTTOM ((ptr_t)0x16fdfffff)
 #     define USE_MMAP_ANON
 #     define MPROTECT_VDB
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <unistd.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)getpagesize()
       /* FIXME: There seems to be some issues with trylock hanging on   */
       /* darwin. This should be looked into some more.                  */
 #       undef STACK_GRAN
 #       define STACK_GRAN 0x10000000
 #       ifdef __ELF__
-#            define DYNAMIC_LOADING
-#            include <features.h>
+#           define DYNAMIC_LOADING
+#           ifdef __cplusplus
+              } /* extern "C" */
+#           endif
+#           include <features.h>
+#           ifdef __cplusplus
+              extern "C" {
+#           endif
 #            if defined(__GLIBC__) && __GLIBC__ >= 2 \
                 || defined(HOST_ANDROID) || defined(HOST_TIZEN)
 #                define SEARCH_FOR_DATA_START
 #     define STACKBOTTOM ((ptr_t)0x30000000)
 #     define USE_MMAP_ANON
 #     define MPROTECT_VDB
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <unistd.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)getpagesize()
       /* FIXME: There seems to be some issues with trylock hanging on   */
       /* darwin. This should be looked into some more.                  */
 #   ifdef OPENBSD
 #     define OS_TYPE "OPENBSD"
 #     ifndef GC_OPENBSD_THREADS
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/param.h>
 #       include <uvm/uvm_extern.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USRSTACK
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       else
 #   ifdef OPENBSD
 #     define OS_TYPE "OPENBSD"
 #     ifndef GC_OPENBSD_THREADS
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/param.h>
 #       include <uvm/uvm_extern.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USRSTACK
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       else
 #   ifdef SN_TARGET_ORBIS
 #     define DATASTART (ptr_t)ALIGNMENT
 #     define DATAEND (ptr_t)ALIGNMENT
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <pthread.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
       void *ps4_get_stack_bottom(void);
 #     define STACKBOTTOM ((ptr_t)ps4_get_stack_bottom())
 #   endif
 #       define OS_TYPE "OPENBSD"
 #       define ELF_CLASS ELFCLASS64
 #       ifndef GC_OPENBSD_THREADS
+#         ifdef __cplusplus
+            } /* extern "C" */
+#         endif
 #         include <sys/param.h>
 #         include <uvm/uvm_extern.h>
+#         ifdef __cplusplus
+            extern "C" {
+#         endif
 #         ifdef USRSTACK
 #           define STACKBOTTOM ((ptr_t)USRSTACK)
 #         else
             /* and can't deal with the signals.                         */
 #       endif
 #       ifdef __ELF__
-#            define DYNAMIC_LOADING
-#            include <features.h>
-#            define SEARCH_FOR_DATA_START
-             extern int _end[];
-#            define DATAEND ((ptr_t)(_end))
+#           define DYNAMIC_LOADING
+#           ifdef __cplusplus
+              } /* extern "C" */
+#           endif
+#           include <features.h>
+#           ifdef __cplusplus
+              extern "C" {
+#           endif
+#           define SEARCH_FOR_DATA_START
+            extern int _end[];
+#           define DATAEND ((ptr_t)(_end))
 #       else
              extern int etext[];
 #            define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
 #       if defined(__GLIBC__) && !defined(__UCLIBC__)
           /* Workaround lock elision implementation for some glibc.     */
 #         define GLIBC_2_19_TSX_BUG
+#         ifdef __cplusplus
+            } /* extern "C" */
+#         endif
 #         include <gnu/libc-version.h> /* for gnu_get_libc_version() */
+#         ifdef __cplusplus
+            extern "C" {
+#         endif
 #       endif
 #   endif
 #   ifdef DARWIN
 #     define STACKBOTTOM ((ptr_t)0x7fff5fc00000)
 #     define USE_MMAP_ANON
 #     define MPROTECT_VDB
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <unistd.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)getpagesize()
       /* There seems to be some issues with trylock hanging on darwin.  */
       /* This should be looked into some more.                          */
 #   endif
 #   ifdef HAIKU
 #     define OS_TYPE "HAIKU"
+#     ifdef __cplusplus
+        } /* extern "C" */
+#     endif
 #     include <OS.h>
+#     ifdef __cplusplus
+        extern "C" {
+#     endif
 #     define GETPAGESIZE() (unsigned)B_PAGE_SIZE
       extern int etext[];
 #     define DATASTART ((ptr_t)((((word)etext) + 0xfff) & ~0xfff))
 #       define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext)
 #       define DATASTART_IS_FUNC
 #       define DATAEND ((ptr_t)(_end))
-/*      # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7,      */
-/*      but reportedly breaks under 2.8.  It appears that the stack     */
-/*      base is a property of the executable, so this should not break  */
-/*      old executables.                                                */
-/*      HEURISTIC2 probably works, but this appears to be preferable.   */
-/*      Apparently USRSTACK is defined to be USERLIMIT, but in some     */
-/*      installations that's undefined.  We work around this with a     */
-/*      gross hack:                                                     */
+        /* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7,   */
+        /* but reportedly breaks under 2.8.  It appears that the stack  */
+        /* base is a property of the executable, so this should not     */
+        /* break old executables.                                       */
+        /* HEURISTIC2 probably works, but this appears to be preferable.*/
+        /* Apparently USRSTACK is defined to be USERLIMIT, but in some  */
+        /* installations that's undefined.  We work around this with a  */
+        /* gross hack:                                                  */
+#       ifdef __cplusplus
+          } /* extern "C" */
+#       endif
 #       include <sys/vmparam.h>
+#       ifdef __cplusplus
+          extern "C" {
+#       endif
 #       ifdef USERLIMIT
           /* This should work everywhere, but doesn't.  */
 #         define STACKBOTTOM ((ptr_t)USRSTACK)
 #       define LINUX_STACKBOTTOM
 #       define MPROTECT_VDB
 #       ifdef __ELF__
-#            define DYNAMIC_LOADING
-#            include <features.h>
+#           define DYNAMIC_LOADING
+#           ifdef __cplusplus
+              } /* extern "C" */
+#           endif
+#           include <features.h>
+#           ifdef __cplusplus
+              extern "C" {
+#           endif
 #            if defined(__GLIBC__) && __GLIBC__ >= 2
 #                define SEARCH_FOR_DATA_START
 #            else
 
 #if (defined(SVR4) || defined(HOST_ANDROID) || defined(HOST_TIZEN)) \
     && !defined(GETPAGESIZE)
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
 # include <unistd.h>
+# ifdef __cplusplus
+    extern "C" {
+# endif
 # define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE)
 #endif
 
 #ifndef GETPAGESIZE
 # if defined(SOLARIS) || defined(IRIX5) || defined(LINUX) \
      || defined(NETBSD) || defined(FREEBSD) || defined(HPUX)
+#   ifdef __cplusplus
+      } /* extern "C" */
+#   endif
 #   include <unistd.h>
+#   ifdef __cplusplus
+      extern "C" {
+#   endif
 # endif
 # define GETPAGESIZE() (unsigned)getpagesize()
 #endif
 #endif
 
 #ifdef GC_OPENBSD_THREADS
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
 # include <sys/param.h>
+# ifdef __cplusplus
+    extern "C" {
+# endif
   /* Prior to 5.2 release, OpenBSD had user threads and required        */
   /* special handling.                                                  */
 # if OpenBSD < 201211
 # endif
 #endif /* GC_PRIVATE_H */
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif /* GCCONFIG_H */
index ec5dfea622e9a600a3065d70b121b16cb7e09999..2293aada0f8de83a78e7f49ba6b74ca02d5496a5 100644 (file)
 #ifndef GC_PTHREAD_STOP_WORLD_H
 #define GC_PTHREAD_STOP_WORLD_H
 
+/* Note: never put extern "C" around an #include.                       */
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 struct thread_stop_info {
 #   if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
       volatile AO_t last_stop_count;
@@ -46,4 +51,8 @@ struct thread_stop_info {
 
 GC_INNER void GC_stop_init(void);
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif
index 12c3f1af1a58d343d2bcedfcd5c47d1eb7247494..c9f9976127561d88f16517f7a1b47c25d5f27558 100644 (file)
 # include "dbg_mlc.h" /* for oh type */
 #endif
 
+/* Note: never put extern "C" around an #include.                       */
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* We use the allocation lock to protect thread-related data structures. */
 
 /* The set of all known threads.  We intercept thread creation and      */
@@ -176,6 +181,10 @@ GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
                                         struct GC_stack_base *sb, void *arg);
 GC_INNER_PTHRSTART void GC_thread_exit_proc(void *);
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif /* GC_PTHREADS && !GC_WIN32_THREADS */
 
 #endif /* GC_PTHREAD_SUPPORT_H */
index ccca009dff09830d1a54e9825002ab901959ddef..ab864750e464d641acaf73eb9fe91d00f1a13f5d 100644 (file)
 
 #include "gc_atomic_ops.h"
 
+/* Note: never put extern "C" around an #include.       */
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* Called during key creation or setspecific.           */
 /* For the GC we already hold lock.                     */
 /* Currently allocated objects leak on thread exit.     */
@@ -99,3 +104,7 @@ GC_INLINE void * GC_getspecific(tsd * key)
     }
     return GC_slow_getspecific(key, qtid, entry_ptr);
 }
+
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
index 9f61d8d873286bce606bbc8b04ec52dca5fdc706..32bafd827fbf4e3d533c2e116a466d4f75d42460 100644 (file)
 # error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
 #endif
 
+#include <stdlib.h>
+
+/* Note: never put extern "C" around an #include.               */
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 #if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) \
     && !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) \
     && !defined(USE_CUSTOM_SPECIFIC)
@@ -71,8 +78,6 @@
 # endif
 #endif
 
-#include <stdlib.h>
-
 #ifndef THREAD_FREELISTS_KINDS
 # ifdef ENABLE_DISCLAIM
 #   define THREAD_FREELISTS_KINDS (NORMAL+2)
@@ -128,11 +133,17 @@ typedef struct thread_local_freelists {
 # define GC_remove_specific_after_fork(key, t) (void)0
   typedef void * GC_key_t;
 #elif defined(USE_WIN32_SPECIFIC)
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
 # ifndef WIN32_LEAN_AND_MEAN
 #   define WIN32_LEAN_AND_MEAN 1
 # endif
 # define NOSERVICE
 # include <windows.h>
+# ifdef __cplusplus
+    extern "C" {
+# endif
 # define GC_getspecific TlsGetValue
 # define GC_setspecific(key, v) !TlsSetValue(key, v)
         /* We assume 0 == success, msft does the opposite.      */
@@ -147,7 +158,13 @@ typedef struct thread_local_freelists {
 # define GC_remove_specific_after_fork(key, t) (void)0
   typedef DWORD GC_key_t;
 #elif defined(USE_CUSTOM_SPECIFIC)
+# ifdef __cplusplus
+    } /* extern "C" */
+# endif
 # include "private/specific.h"
+# ifdef __cplusplus
+    extern "C" {
+# endif
 #else
 # error implement me
 #endif
@@ -182,6 +199,10 @@ extern
 /* for cleanup on thread exit.  But the thread support layer makes sure */
 /* that GC_thread_key is traced, if necessary.                          */
 
+#ifdef __cplusplus
+  } /* extern "C" */
+#endif
+
 #endif /* THREAD_LOCAL_ALLOC */
 
 #endif /* GC_THREAD_LOCAL_ALLOC_H */