Patchwork fix C++11 thread support for win32

login
register
mail settings
Submitter Thorsten Wilmer
Date Aug. 28, 2014, 6:57 p.m.
Message ID <CAKMJ56w7mtK1GZSUKUuU9DNXh95fixHdDjPZeogwGmQd1L7cYg@mail.gmail.com>
Download mbox | patch
Permalink /patch/384006/
State New
Headers show

Comments

Thorsten Wilmer - Aug. 28, 2014, 6:57 p.m.
Hi,

I stumbled over the problem, that on win32 c++11's Thread support is
broken. I found a patch from  Tomohiro Kashiwada, who did a great job.
Only he didn't pursue to have it integrated since more than two years.

I have applied his patch and fixed some compiler warnings and obvious
cast/pointer problems, where the win32 api and the pthread api don't
match. Also I verified that libstdc++'s configure script detects that
thread support can be activated.

Please consider the patch below for inclusion. If you see any blocking
points, let me know, I'll try to address them as I would like to use
my C++11 programs  on win32 without hassle and a fresh compiler.

The patch is against current git mirror. It compiles without error and
the compiled source code survived some example programs for threads
and my own complex program, which is using threads, mutex and
condition variables.

I compiled the complete tool chain from source, this is my gcc configuration:
../gcc/configure --prefix=/usr/local/gcc/git-mingw
--with-gmp=/usr/local/gcc/git-mingw --target=x86_64-w64-mingw32
--enable-targets=all --disable-multilib

Here the random output of the example program:
Z:\>a.exe
Thread Thread 2 executing
1 executing
Thread Thread 2 executing
1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread Thread 2 executing
1 executing
Final value of n is 5

Kind Regards,
 Thorsten Wilmer


From 9591d02da5e6131e4a79259ed952d52dcecb86ac Mon Sep 17 00:00:00 2001
From: Thorsten Wilmer <wilmer.thorsten@gmail.com>
Date: Thu, 28 Aug 2014 23:37:41 +0530
Subject: [PATCH] fix C++11 thread support for win32

Based on
Implemented Condition Variable by Tomohiro Kashiwada
   <kikairoya@gmail.com>.

Fixed compile warnings and added some error handling.
---
 libgcc/config/i386/gthr-win32.c | 290 ++++++++++++++++++++++++++++++++++++++++
 libgcc/config/i386/gthr-win32.h | 220 ++++++++++++++++++++++++++++--
 2 files changed, 502 insertions(+), 8 deletions(-)

 #endif

 /* Windows32 threads specific definitions. The windows32 threading model
@@ -65,6 +72,8 @@ see the files COPYING3 and COPYING.RUNTIME
respectively.  If not, see
    needs to use Structured Exception Handling on Windows32.  */

 #define __GTHREADS 1
+#define __GTHREADS_CXX0X 1
+#define __GTHREAD_HAS_COND 1

 #include <errno.h>
 #ifdef __MINGW32__
@@ -120,7 +129,7 @@ __gthread_objc_thread_detach (void (*func)(void
*arg), void *arg)
   DWORD thread_id = 0;
   HANDLE win32_handle;

-  if (!(win32_handle = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) func,
+  if (!(win32_handle = CreateThread (0, 0, (LPTHREAD_START_ROUTINE) func,
      arg, 0, &thread_id)))
     thread_id = 0;

@@ -240,7 +249,7 @@ __gthread_objc_thread_get_data (void)
 int
 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
 {
-  if ((mutex->backend = (void *) CreateMutex (NULL, 0, NULL)) == NULL)
+  if ((mutex->backend = (void *) CreateMutex (0, 0, 0)) == 0)
     return -1;
   else
     return 0;
@@ -358,6 +367,26 @@ typedef struct {
   void *sema;
 } __gthread_recursive_mutex_t;

+typedef struct {
+  long counter;
+  void *pcs;
+  void *sema;
+} __gthread_cond_t;
+
+
+typedef struct {
+  void *handle;
+  unsigned id;
+  void *(*func) (void *);
+  void *arg;
+} __gthread_solid_t;
+typedef __gthread_solid_t *__gthread_t;
+
+typedef struct {
+  time_t tv_sec;
+  long tv_nsec;
+} __gthread_time_t;
+
 #define __GTHREAD_ONCE_INIT {0, -1}
 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
 #define __GTHREAD_MUTEX_INIT_DEFAULT {-1, 0}
@@ -365,6 +394,8 @@ typedef struct {
   __gthread_recursive_mutex_init_function
 #define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}

+#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
+
 #if defined (_WIN32) && !defined(__CYGWIN__)
 #define MINGW32_SUPPORTS_MT_EH 1
 /* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
@@ -431,6 +462,31 @@ extern int __gthr_win32_recursive_mutex_unlock
(__gthread_recursive_mutex_t *);
 extern void __gthr_win32_mutex_destroy (__gthread_mutex_t *);
 extern int
   __gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t *);
+extern int __gthr_win32_cond_init (__gthread_cond_t *, void *);
+extern int __gthr_win32_cond_destroy (__gthread_cond_t *);
+extern int __gthr_win32_cond_broadcast (__gthread_cond_t *);
+extern int __gthr_win32_cond_wait (__gthread_cond_t *, __gthread_mutex_t *);
+extern int __gthr_win32_cond_wait_recursive (__gthread_cond_t *,
+     __gthread_recursive_mutex_t *);
+extern int __gthr_win32_create (__gthread_t *, void *(*func) (void *), void *);
+extern int __gthr_win32_join (__gthread_t, void **);
+extern int __gthr_win32_detach (__gthread_t);
+extern int __gthr_win32_equal (__gthread_t, __gthread_t);
+extern __gthread_t __gthr_win32_self (void);
+extern int __gthr_win32_yield (void);
+extern int __gthr_win32_mutex_timedlock (__gthread_mutex_t *,
+ const __gthread_time_t *);
+extern int
+  __gthr_win32_recursive_mutex_timedlock (__gthread_recursive_mutex_t *,
+  const __gthread_time_t *);
+extern int __gthr_win32_cond_signal (__gthread_cond_t *);
+extern int __gthr_win32_cond_timedwait (__gthread_cond_t *,
+ __gthread_mutex_t *,
+ const __gthread_time_t *);
+extern int
+__gthr_win32_cond_timedwait_recursive (__gthread_cond_t *,
+       __gthread_recursive_mutex_t *,
+       const __gthread_time_t *);

 static inline int
 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
@@ -543,6 +599,154 @@ __gthread_recursive_mutex_destroy
(__gthread_recursive_mutex_t *__mutex)
   return __gthr_win32_recursive_mutex_destroy (__mutex);
 }

+static inline int
+__gthread_cond_init_function (__gthread_cond_t *__cond)
+{
+  return __gthr_win32_cond_init (__cond, 0);
+}
+
+static inline int
+__gthread_cond_init (__gthread_cond_t *__cond, void *__attr)
+{
+  return __gthr_win32_cond_init (__cond, __attr);
+}
+
+static inline int
+__gthread_cond_destroy (__gthread_cond_t *__cond)
+{
+  return __gthr_win32_cond_destroy (__cond);
+}
+
+static inline int
+__gthread_cond_broadcast (__gthread_cond_t *__cond)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_cond_broadcast (__cond);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_cond_wait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_cond_wait (__cond, __mutex);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_cond_wait_recursive (__gthread_cond_t *__cond,
+       __gthread_recursive_mutex_t *__mutex)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_cond_wait_recursive (__cond, __mutex);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_create (__gthread_t *__pthr, void *(*__func) (void *), void *__args)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_create (__pthr, __func, __args);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_join (__gthread_t __thr, void **__value_ptr)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_join (__thr, __value_ptr);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_detach (__gthread_t __thr)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_detach (__thr);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_equal (__gthread_t __t1, __gthread_t __t2)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_equal (__t1, __t2);
+  else
+    return 0;
+}
+
+static inline __gthread_t
+__gthread_self (void)
+{
+  return __gthr_win32_self ();
+}
+
+static inline int
+__gthread_yield (void)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_yield ();
+  else
+    return 0;
+}
+
+static inline int
+__gthread_mutex_timedlock (__gthread_mutex_t *__mutex,
+   const __gthread_time_t *__abs_timeout)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_mutex_timedlock (__mutex, __abs_timeout);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_recursive_mutex_timedlock (__gthread_recursive_mutex_t *__mutex,
+     const __gthread_time_t *__abs_timeout)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_recursive_mutex_timedlock (__mutex, __abs_timeout);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_cond_signal (__gthread_cond_t *__cond)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_cond_signal (__cond);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_cond_timedwait (__gthread_cond_t *__cond, __gthread_mutex_t *__mutex,
+  const __gthread_time_t *__abs_timeout)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_cond_timedwait (__cond, __mutex, __abs_timeout);
+  else
+    return 0;
+}
+
+static inline int
+__gthread_cond_timedwait_recursive (__gthread_cond_t *__cond,
+    __gthread_recursive_mutex_t *__mutex,
+    const __gthread_time_t *__abs_timeout)
+{
+  if (__gthread_active_p ())
+    return __gthr_win32_cond_timedwait_recursive (__cond, __mutex,
+  __abs_timeout);
+  else
+    return 0;
+}
+
 #else /* ! __GTHREAD_HIDE_WIN32API */

 #include <windows.h>
@@ -553,7 +757,7 @@ __gthread_once (__gthread_once_t *__once, void
(*__func) (void))
 {
   if (! __gthread_active_p ())
     return -1;
-  else if (__once == NULL || __func == NULL)
+  else if (__once == 0 || __func == 0)
     return EINVAL;

   if (! __once->done)
@@ -635,7 +839,7 @@ static inline void
 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
 {
   __mutex->counter = -1;
-  __mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
+  __mutex->sema = CreateSemaphoreW (0, 0, 65535, 0);
 }

 static inline void
@@ -686,7 +890,7 @@ __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
   if (__gthread_active_p ())
     {
       if (InterlockedDecrement (&__mutex->counter) >= 0)
- return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
+ return ReleaseSemaphore (__mutex->sema, 1, 0) ? 0 : 1;
     }
   return 0;
 }
@@ -697,7 +901,7 @@ __gthread_recursive_mutex_init_function
(__gthread_recursive_mutex_t *__mutex)
   __mutex->counter = -1;
   __mutex->depth = 0;
   __mutex->owner = 0;
-  __mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
+  __mutex->sema = CreateSemaphore (0, 0, 65535, 0);
 }

 static inline int
@@ -762,7 +966,7 @@ __gthread_recursive_mutex_unlock
(__gthread_recursive_mutex_t *__mutex)
   __mutex->owner = 0;

   if (InterlockedDecrement (&__mutex->counter) >= 0)
-    return ReleaseSemaphore (__mutex->sema, 1, NULL) ? 0 : 1;
+    return ReleaseSemaphore (__mutex->sema, 1, 0) ? 0 : 1;
  }
     }
   return 0;

Patch

diff --git a/libgcc/config/i386/gthr-win32.c b/libgcc/config/i386/gthr-win32.c
index eec16b3..10769a7 100644
--- a/libgcc/config/i386/gthr-win32.c
+++ b/libgcc/config/i386/gthr-win32.c
@@ -5,6 +5,8 @@ 
    Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
    Modified and moved to separate file by Danny Smith
    <dannysmith@users.sourceforge.net>.
+   Implemented Condition Variable by Tomohiro Kashiwada
+   <kikairoya@gmail.com>.

 This file is part of GCC.

@@ -28,6 +30,7 @@  see the files COPYING3 and COPYING.RUNTIME
respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */

 #include <windows.h>
+#include <process.h>
 #ifndef __GTHREAD_HIDE_WIN32API
 # define __GTHREAD_HIDE_WIN32API 1
 #endif
@@ -259,9 +262,296 @@  __gthr_win32_recursive_mutex_unlock
(__gthread_recursive_mutex_t *mutex)
   return 0;
 }

+
 int
 __gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t *mutex)
 {
   CloseHandle ((HANDLE) mutex->sema);
   return 0;
 }
+
+
+static DWORD
+gthread_calc_time_offset (const __gthread_time_t *abs_time)
+{
+  FILETIME ft;
+  LONGLONG ll;
+  LONGLONG ret;
+  GetSystemTimeAsFileTime (&ft);
+  ll = ((LONGLONG)ft.dwHighDateTime << 32) + ft.dwLowDateTime;
+  ret = (((LONGLONG)abs_time->tv_sec * 10000000 + abs_time->tv_nsec / 100)
+ - (ll - 116444736000000000)) / 10000;
+  if (ret < 0)
+    return 0;
+  if (ret > 0x7FFFFFFF)
+    return 0x7FFFFFFF;
+  return ret;
+}
+
+int
+__gthr_win32_cond_init (__gthread_cond_t *cond,
+ void *attr __attribute__((unused)))
+{
+  cond->counter = -1;
+  cond->pcs = malloc (sizeof (CRITICAL_SECTION));
+  InitializeCriticalSection ((LPCRITICAL_SECTION)cond->pcs);
+  cond->sema = CreateSemaphore (NULL, 0, 65535, NULL);
+  return 0;
+}
+
+int
+__gthr_win32_cond_destroy (__gthread_cond_t *cond)
+{
+  __gthread_cond_broadcast (cond);
+  free (cond->pcs);
+  CloseHandle ((HANDLE)cond->sema);
+  return 0;
+}
+
+int
+__gthr_win32_cond_broadcast (__gthread_cond_t *cond)
+{
+  EnterCriticalSection (cond->pcs);
+  if (cond->counter >= 0)
+    ReleaseSemaphore (cond->sema, cond->counter+1, NULL);
+  cond->counter = -1;
+  LeaveCriticalSection (cond->pcs);
+  return 0;
+}
+
+static int
+cond_wait_impl (__gthread_cond_t *cond,
+ __gthread_mutex_t *mutex, DWORD timeout)
+{
+  EnterCriticalSection (cond->pcs);
+  ++cond->counter;
+  LeaveCriticalSection (cond->pcs);
+  if (SignalObjectAndWait (mutex->sema, cond->sema, timeout, FALSE)
+      != WAIT_OBJECT_0)
+    {
+      EnterCriticalSection (cond->pcs);
+      --cond->counter;
+      LeaveCriticalSection (cond->pcs);
+    }
+  WaitForSingleObject (mutex->sema, INFINITE);
+  return 0;
+}
+
+static int
+cond_wait_recursive_impl (__gthread_cond_t *cond,
+  __gthread_recursive_mutex_t *mutex, DWORD timeout)
+{
+  EnterCriticalSection (cond->pcs);
+  ++cond->counter;
+  LeaveCriticalSection (cond->pcs);
+  if (SignalObjectAndWait (mutex->sema, cond->sema, timeout, FALSE)
+      != WAIT_OBJECT_0)
+    {
+      EnterCriticalSection (cond->pcs);
+      --cond->counter;
+      LeaveCriticalSection (cond->pcs);
+    }
+  WaitForSingleObject (mutex->sema, INFINITE);
+  return 0;
+}
+
+int
+__gthr_win32_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return cond_wait_impl (cond, mutex, INFINITE);
+}
+
+int
+__gthr_win32_cond_wait_recursive (__gthread_cond_t *cond,
+  __gthread_recursive_mutex_t *mutex)
+{
+  return cond_wait_recursive_impl (cond, mutex, INFINITE);
+}
+
+static unsigned
+get_thread_id (__gthread_t thr)
+{
+  if (thr)
+    return thr->id;
+  return GetCurrentThreadId ();
+}
+
+static DWORD gthr_gthread_t_get_slot (void)
+{
+  static DWORD gthread_slot = 0xFFFFFFFF;
+  if (gthread_slot == 0xFFFFFFFF)
+    {
+      DWORD s = TlsAlloc ();
+      if ((DWORD) __GTHR_W32_InterlockedCompareExchange((long
int*)(&gthread_slot), s, 0xFFFFFFFF)
+  != 0xFFFFFFFFu)
+ {
+  TlsFree (s);
+  return gthread_slot;
+ }
+      else
+ {
+  __gthread_t thr = (__gthread_t)malloc (sizeof (__gthread_solid_t));
+  thr->func = NULL;
+  thr->arg = NULL;
+  thr->id = GetCurrentThreadId ();
+  DuplicateHandle(GetCurrentProcess (), GetCurrentThread (),
+  GetCurrentProcess (), (HANDLE *)&thr->id,
+  0, FALSE, DUPLICATE_SAME_ACCESS);
+  TlsSetValue(gthread_slot, thr);
+ }
+    }
+  return gthread_slot;
+}
+
+static unsigned __stdcall
+gthr_entry_stub (void *arg)
+{
+  __gthread_t p = (__gthread_t)arg;
+  TlsSetValue (gthr_gthread_t_get_slot (), arg);
+  /* the return code of the thread function is ignored as we have
here anyway only
+     a unsigned which is not enough to pass a full pointer.
+  */
+  void *ret=(*p->func) (p->arg);
+  if(ret!=0)
+  {
+    DWORD result=*(DWORD*)(ret);
+    ExitThread(result);
+  }
+  else
+  {
+    ExitThread(0);
+  }
+
+  return 0 ;
+}
+
+
+int
+__gthr_win32_create (__gthread_t *thrp, void *(*func) (void *), void *arg)
+{
+  gthr_gthread_t_get_slot ();
+  *thrp = (__gthread_t)malloc (sizeof (__gthread_solid_t));
+  (*thrp)->func = func;
+  (*thrp)->arg = arg;
+  (*thrp)->handle = (void *)_beginthreadex (NULL, 0, &gthr_entry_stub, *thrp,
+    0, &(*thrp)->id);
+  if((*thrp)->handle == 0)
+  {
+    return -1;
+  }
+
+  return 0;
+}
+
+int
+__gthr_win32_join (__gthread_t thr, void **pv)
+{
+  WaitForSingleObject ((HANDLE)thr->handle, INFINITE);
+
+  if (pv)
+  {
+     LPDWORD r;
+     r=(LPDWORD)*pv;
+     GetExitCodeThread ((HANDLE)thr->handle, r);
+  }
+  __gthr_win32_detach (thr);
+  return 0;
+}
+
+int __gthr_win32_detach (__gthread_t thr)
+{
+  CloseHandle ((HANDLE)thr->handle);
+  free (thr);
+  return 0;
+}
+
+int __gthr_win32_equal (__gthread_t t1, __gthread_t t2)
+{
+  return get_thread_id (t1) == get_thread_id (t2);
+}
+
+__gthread_t
+__gthr_win32_self (void)
+{
+  return (__gthread_t)TlsGetValue (gthr_gthread_t_get_slot ());
+}
+
+int
+__gthr_win32_yield (void)
+{
+  Sleep(0);
+  return 0;
+}
+
+int
+__gthr_win32_mutex_timedlock (__gthread_mutex_t *mutex,
+      const __gthread_time_t *abs_timeout)
+{
+  if (InterlockedIncrement (&mutex->counter) == 0 ||
+      WaitForSingleObject (mutex->sema, gthread_calc_time_offset (abs_timeout))
+      == WAIT_OBJECT_0)
+    return 0;
+  else
+    {
+      InterlockedDecrement (&mutex->counter);
+      return 0;
+    }
+}
+
+int
+__gthr_win32_recursive_mutex_timedlock (__gthread_recursive_mutex_t *mutex,
+ const __gthread_time_t *abs_timeout)
+{
+  DWORD me = GetCurrentThreadId ();
+  if (InterlockedIncrement (&mutex->counter) == 0)
+    {
+      mutex->depth = 1;
+      mutex->owner = me;
+    }
+  else if (mutex->owner == me)
+    {
+      InterlockedDecrement (&mutex->counter);
+      ++(mutex->depth);
+    }
+  else if (WaitForSingleObject (mutex->sema,
+ gthread_calc_time_offset (abs_timeout))
+   == WAIT_OBJECT_0)
+    {
+      mutex->depth = 1;
+      mutex->owner = me;
+    }
+  else
+    {
+      InterlockedDecrement (&mutex->counter);
+    }
+  return 0;
+}
+
+int
+__gthr_win32_cond_signal (__gthread_cond_t *cond)
+{
+  EnterCriticalSection (cond->pcs);
+  if (cond->counter >= 0)
+    {
+      --cond->counter;
+      ReleaseSemaphore (cond->sema, 1, NULL);
+    }
+  LeaveCriticalSection (cond->pcs);
+  return 0;
+}
+
+int
+__gthr_win32_cond_timedwait (__gthread_cond_t *cond, __gthread_mutex_t *mutex,
+     const __gthread_time_t *abs_timeout)
+{
+  return cond_wait_impl (cond, mutex, gthread_calc_time_offset (abs_timeout));
+}
+
+int
+__gthr_win32_cond_timedwait_recursive (__gthread_cond_t *cond,
+       __gthread_recursive_mutex_t *mutex,
+       const __gthread_time_t *abs_timeout)
+{
+  return cond_wait_recursive_impl (cond, mutex,
+   gthread_calc_time_offset (abs_timeout));
+}
diff --git a/libgcc/config/i386/gthr-win32.h b/libgcc/config/i386/gthr-win32.h
index c295fd5..af1f7cc 100644
--- a/libgcc/config/i386/gthr-win32.h
+++ b/libgcc/config/i386/gthr-win32.h
@@ -3,6 +3,8 @@ 

 /* Copyright (C) 1999-2014 Free Software Foundation, Inc.
    Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
+   Implemented Condition Variable by Tomohiro Kashiwada
+   <kikairoya@gmail.com>.

 This file is part of GCC.

@@ -29,8 +31,13 @@  see the files COPYING3 and COPYING.RUNTIME
respectively.  If not, see
 #define GCC_GTHR_WIN32_H

 /* Make sure CONST_CAST2 (origin in system.h) is declared.  */
+#undef CONST_CAST2
 #ifndef CONST_CAST2
-#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union
{FROMTYPE _q; TOTYPE _nq;})(X))._nq)
+#ifdef __cplusplus
+#define CONST_CAST2(TOTYPE,FROMTYPE,X) (const_cast<TOTYPE> (X))
+#else
+#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union
{FROMTYPE _q; TOTYPE _nqtwi;})(X))._nqtwi)
+#endif