psmedley / gcc

GNU General Public License v2.0
7 stars 1 forks source link

C++11 std::thread support lack #21

Closed komh closed 8 years ago

komh commented 8 years ago

Hi/2.

C++11 std::thread support lacks.

// cxx11thread.cpp
#include <iostream>
#include <thread>

void func1()
{
    std::cout << __func__ << "\n";
}

void func2()
{
    std::cout << __func__ << "\n";
}

int main()
{
    std::thread th1( func1 );
    std::thread th2( func2 );

    th1.join();
    th2.join();

    std::cout << "Bye\n";

    return 0;
}
g++ -std=c++11 cxx11thread.cpp

cxx11thread.cpp: In function 'int main()':
cxx11thread.cpp:16:5: error: 'thread' is not a member of 'std'
     std::thread th1( func1 );
     ^
cxx11thread.cpp:17:5: error: 'thread' is not a member of 'std'
     std::thread th2( func2 );
     ^
cxx11thread.cpp:19:5: error: 'th1' was not declared in this scope
     th1.join();
     ^
cxx11thread.cpp:20:5: error: 'th2' was not declared in this scope
     th2.join();
     ^
komh commented 8 years ago

Here is the patch to support C++11 thread.

Review, please...

From 197d62ec96d727bb926445701dd0abad476de508 Mon Sep 17 00:00:00 2001
From: KO Myung-Hun <komh@chollian.net>
Date: Sun, 31 Jan 2016 21:31:33 +0900
Subject: [PATCH] OS/2: add C++11 thread support

    modified:   libgcc/config.host
    modified:   libgcc/config/i386/libgcc-emx.ver
    new file:   libgcc/config/i386/t-gthr-os2
    new file:   libgcc/gthr-os2.c
    modified:   libgcc/gthr-os2.h
---
 libgcc/config.host                |   5 +
 libgcc/config/i386/libgcc-emx.ver |  26 +++
 libgcc/config/i386/t-gthr-os2     |   2 +
 libgcc/gthr-os2.c                 | 426 ++++++++++++++++++++++++++++++++++++++
 libgcc/gthr-os2.h                 | 234 ++++++++++++++++-----
 5 files changed, 636 insertions(+), 57 deletions(-)
 create mode 100644 libgcc/config/i386/t-gthr-os2
 create mode 100644 libgcc/gthr-os2.c

diff --git a/libgcc/config.host b/libgcc/config.host
index 9f021a1..c92fdb9 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -686,6 +686,11 @@ i[34567]86-*-interix[3-9]*)
    ;;
 i*86-pc-*emx)      # i?86 running OS/2
    tmake_file="$tmake_file i386/t-emx"
+   case ${target_thread_file} in
+     os2)
+       tmake_file="$tmake_file i386/t-gthr-os2"
+       ;;
+   esac
    extra_parts="$extra_parts emx-ctordtor.o"
    host_exeext=.exe
    ;;
diff --git a/libgcc/config/i386/libgcc-emx.ver b/libgcc/config/i386/libgcc-emx.ver
index 03ba5ec..b8fecac 100644
--- a/libgcc/config/i386/libgcc-emx.ver
+++ b/libgcc/config/i386/libgcc-emx.ver
@@ -19,3 +19,29 @@
 # Export custom EMX/KLIBC build symbols

 __chkstk_ms
+
+# __GTHREADS
+__gthread_os2_mutex_init
+__gthread_os2_mutex_destroy
+__gthread_os2_mutex_lock
+__gthread_os2_mutex_trylock
+__gthread_os2_mutex_unlock
+
+# __GTHREAD_HAS_COND
+__gthread_os2_cond_init
+__gthread_os2_cond_destroy
+__gthread_os2_cond_broadcast
+__gthread_os2_cond_wait
+__gthread_os2_cond_wait_recursive
+
+# __GTHREADS_CXX0X
+__gthread_os2_create
+__gthread_os2_join
+__gthread_os2_detach
+__gthread_os2_equal
+__gthread_os2_self
+__gthread_os2_yield
+__gthread_os2_mutex_timedlock
+__gthread_os2_recursive_mutex_timedlock
+__gthread_os2_cond_signal
+__gthread_os2_cond_timedwait
diff --git a/libgcc/config/i386/t-gthr-os2 b/libgcc/config/i386/t-gthr-os2
new file mode 100644
index 0000000..4cf4e55
--- /dev/null
+++ b/libgcc/config/i386/t-gthr-os2
@@ -0,0 +1,2 @@
+# We hide calls to OS/2 APIs needed for OS/2 thread support here:
+LIB2ADD = $(srcdir)/gthr-os2.c
diff --git a/libgcc/gthr-os2.c b/libgcc/gthr-os2.c
new file mode 100644
index 0000000..bbbc3ff
--- /dev/null
+++ b/libgcc/gthr-os2.c
@@ -0,0 +1,426 @@
+/* Threads compatibily routines for libgcc2.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+   Contributed by KO Myung-Hun <komh@chollian.net>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#define INCL_DOS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/builtin.h>
+#include <sys/fmutex.h>
+#include <sys/time.h>
+
+#include "gthr-os2.h"
+
+void
+__gthread_os2_mutex_init (__gthread_mutex_t *mutex, int recursive)
+{
+  mutex->recursive = recursive;
+  DosCreateMutexSem (NULL, (PHMTX) &mutex->mtx, 0, FALSE);
+}
+
+int
+__gthread_os2_mutex_destroy (__gthread_mutex_t *mutex, int recursive)
+{
+  if (mutex->recursive != recursive)
+    return 1;
+
+  return DosCloseMutexSem ((HMTX) mutex->mtx);
+}
+
+static int
+__gthread_os2_mutex_lock_common (__gthread_mutex_t *mutex, int recursive,
+                                 ULONG ulTimeout)
+{
+  PID pid;
+  TID tid;
+  ULONG ulCount;
+
+  if (mutex->recursive != recursive)
+    return 1;
+
+  /* Initialize static mutex.  */
+  if ((HMTX) mutex->mtx == NULLHANDLE)
+    {
+      /* FIXME: resource leaks.  */
+      _fmutex_request (&mutex->static_lock, _FMR_IGNINT);
+      if ((HMTX) mutex->mtx == NULLHANDLE)
+        __gthread_os2_mutex_init (mutex, recursive);
+      _fmutex_release (&mutex->static_lock);
+    }
+
+  if (DosRequestMutexSem ((HMTX) mutex->mtx, ulTimeout))
+    return 1;
+
+  DosQueryMutexSem ((HMTX) mutex->mtx, &pid, &tid, &ulCount);
+
+  /* non-recursive trylock ? */
+  if (!mutex->recursive && ulTimeout == SEM_IMMEDIATE_RETURN && ulCount > 1)
+    {
+      DosReleaseMutexSem ((HMTX) mutex->mtx);
+
+      return 1;
+    }
+
+  assert (!"Dead lock" || mutex->recursive || ulCount == 1);
+
+  return 0;
+}
+
+int
+__gthread_os2_mutex_lock (__gthread_mutex_t *mutex, int recursive)
+{
+  return __gthread_os2_mutex_lock_common (mutex, recursive,
+                                          SEM_INDEFINITE_WAIT);
+}
+
+int
+__gthread_os2_mutex_trylock (__gthread_mutex_t *mutex, int recursive)
+{
+  return __gthread_os2_mutex_lock_common (mutex, recursive,
+                                          SEM_IMMEDIATE_RETURN);
+}
+
+int
+__gthread_os2_mutex_unlock (__gthread_mutex_t *mutex, int recursive)
+{
+  if (mutex->recursive != recursive)
+    return 1;
+
+  return DosReleaseMutexSem ((HMTX) mutex->mtx);
+}
+
+#ifndef DCE_POSTONE
+#define DCE_POSTONE 0x0800  /* Wake up only one waiter and auto reset */
+#endif
+
+void
+__gthread_os2_cond_init (__gthread_cond_t *cond)
+{
+  DosCreateEventSem (NULL, (PHEV) &cond->ev, DCE_POSTONE, FALSE);
+  cond->waiters = 0;
+}
+
+int
+__gthread_os2_cond_destroy (__gthread_cond_t *cond)
+{
+  return DosCloseEventSem ((HEV) cond->ev);
+}
+
+static void
+__gthread_os2_static_cond_init (__gthread_cond_t *cond)
+{
+  /* FIXME: resource leaks */
+  _fmutex_request (&cond->static_lock, _FMR_IGNINT);
+  if ((HEV) cond->ev == NULLHANDLE)
+     __gthread_os2_cond_init (cond);
+  _fmutex_release (&cond->static_lock);
+}
+
+int
+__gthread_os2_cond_broadcast (__gthread_cond_t *cond)
+{
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  while (!__atomic_cmpxchg32 (&cond->waiters, 0, 0))
+    DosPostEventSem ((HEV) cond->ev);
+
+  return 0;
+}
+
+static int
+__gthread_os2_cond_wait_common (__gthread_cond_t *cond,
+                                __gthread_mutex_t *mutex,
+                                int recursive, ULONG ulTimeout)
+{
+  APIRET rc;
+
+  if (mutex->recursive != recursive)
+    return 1;
+
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  __atomic_increment (&cond->waiters);
+
+  __gthread_os2_mutex_unlock (mutex, recursive);
+
+  rc = DosWaitEventSem ((HEV) cond->ev, ulTimeout);
+
+  __atomic_decrement (&cond->waiters);
+
+  __gthread_os2_mutex_lock (mutex, recursive);
+
+  return rc;
+}
+
+int
+__gthread_os2_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 0, SEM_INDEFINITE_WAIT);
+}
+
+int
+__gthread_os2_cond_wait_recursive (__gthread_cond_t *cond,
+                                   __gthread_recursive_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 1, SEM_INDEFINITE_WAIT);
+}
+
+typedef struct __gthread_os2_s __gthread_os2_t;
+
+struct __gthread_os2_s {
+  __gthread_t tid;
+  void *(*func) (void*);
+  void *args;
+  void *result;
+  HEV hevDone;
+  int detached;
+  __gthread_os2_t *next;
+};
+
+static __gthread_os2_t main_thread =
+  { 1, NULL, NULL, NULL, NULLHANDLE, 0, NULL };
+
+static __gthread_os2_t *__gthread_os2_thread_start = &main_thread;
+
+static __gthread_os2_t *
+__gthread_os2_thread_new (void *(*func) (void*), void *args)
+{
+  __gthread_os2_t *new_thread;
+
+  new_thread = calloc(1, sizeof (*new_thread));
+  if (new_thread)
+    {
+      new_thread->func = func;
+      new_thread->args = args;
+      DosCreateEventSem (NULL, &new_thread->hevDone, 0, FALSE);
+    }
+
+  return new_thread;
+}
+
+static void
+__gthread_os2_thread_free (__gthread_os2_t *thread)
+{
+  if (thread == &main_thread)
+    return;
+
+  DosCloseEventSem (thread->hevDone);
+
+  free (thread);
+}
+
+static __gthread_os2_t *
+__gthread_os2_thread_find (__gthread_t tid)
+{
+  __gthread_os2_t *thread = __gthread_os2_thread_start;
+
+  while (thread && thread->tid != tid)
+    thread = thread->next;
+
+  return thread;
+}
+
+static void
+__gthread_os2_thread_add (__gthread_t tid, __gthread_os2_t *thread)
+{
+  thread->tid = tid;
+  thread->next = __gthread_os2_thread_start;
+
+  __gthread_os2_thread_start = thread;
+}
+
+static void
+__gthread_os2_thread_del (__gthread_t tid)
+{
+  __gthread_os2_t *thread;
+  __gthread_os2_t *prev = NULL;
+
+  for (thread = __gthread_os2_thread_start; thread && thread->tid != tid;
+       thread = thread->next)
+    prev = thread;
+
+  if (!thread || thread == &main_thread)
+    return;
+
+  if (prev)
+    prev->next = thread->next;
+  else /* if (thread == __gthread_os2_thread_start) */
+    __gthread_os2_thread_start = thread->next;
+
+  __gthread_os2_thread_free (thread);
+}
+
+static void thread_entry (void *args)
+{
+  __gthread_os2_t *th = (__gthread_os2_t *)args;
+
+  th->result = th->func(th->args);
+  DosPostEventSem (th->hevDone);
+
+  if (th->detached)
+    __gthread_os2_thread_del (th);
+}
+
+int
+__gthread_os2_create (__gthread_t *thread, void *(*func) (void*), void *args)
+{
+  __gthread_os2_t *th;
+  int tid;
+
+  th = __gthread_os2_thread_new (func, args);
+  if (!th)
+    return ENOMEM;
+
+  tid = _beginthread (thread_entry, NULL, 1024 * 1024, th);
+  if (tid == -1)
+    {
+      __gthread_os2_thread_free (th);
+
+      return 1;
+    }
+
+  __gthread_os2_thread_add (tid, th);
+
+  *thread = tid;
+
+  return 0;
+}
+
+int
+__gthread_os2_join (__gthread_t thread, void **value_ptr)
+{
+  __gthread_os2_t *th;
+
+  th = __gthread_os2_thread_find (thread);
+
+  if (!th || th->detached)
+    return 1;
+
+  if (DosWaitEventSem (th->hevDone, SEM_INDEFINITE_WAIT))
+    return 1;
+
+  if (value_ptr)
+    *value_ptr = th->result;
+
+  __gthread_os2_thread_del (th);
+
+  return 0;
+}
+
+int
+__gthread_os2_detach (__gthread_t thread)
+{
+  __gthread_os2_t *th;
+
+  th = __gthread_os2_thread_find (thread);
+  if (!th)
+    return 1;
+
+  th->detached = 1;
+
+  return 0;
+}
+
+/* Compare threads. Return non-zero if same, otherwise 0.  */
+int
+__gthread_os2_equal (__gthread_t t1, __gthread_t t2)
+{
+  return t1 == t2;
+}
+
+__gthread_t
+__gthread_os2_self (void)
+{
+  return _gettid();
+}
+
+int
+__gthread_os2_yield (void)
+{
+  DosSleep (0);
+
+  return 0;
+}
+
+static ULONG
+__gthread_os2_abs2rem (const __gthread_time_t *abs_timeout)
+{
+  struct timeval tv;
+  ULONG ulNow;
+  ULONG ulDeadline;
+  ULONG ulRemain;
+
+  gettimeofday (&tv, NULL);
+  ulNow = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+  ulDeadline = abs_timeout->tv_sec * 1000 + abs_timeout->tv_nsec / 1000000UL;
+  ulRemain = (ulDeadline > ulNow) ? (ulDeadline - ulNow) : 0;
+
+  return ulRemain;
+}
+
+int
+__gthread_os2_mutex_timedlock (__gthread_mutex_t *mutex,
+                               const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_lock_common (mutex, 0,
+                                          __gthread_os2_abs2rem (abs_timeout));
+}
+
+int
+__gthread_os2_recursive_mutex_timedlock (__gthread_recursive_mutex_t *mutex,
+                                         const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_lock_common (mutex, 1,
+                                          __gthread_os2_abs2rem (abs_timeout));
+}
+
+int
+__gthread_os2_cond_signal (__gthread_cond_t *cond)
+{
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  if (!__atomic_cmpxchg32 (&cond->waiters, 0, 0))
+    DosPostEventSem ((HEV) cond->ev);
+
+  return 0;
+}
+
+int
+__gthread_os2_cond_timedwait (__gthread_cond_t *cond, __gthread_mutex_t *mutex,
+                              const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 0,
+                                         __gthread_os2_abs2rem (abs_timeout));
+}
diff --git a/libgcc/gthr-os2.h b/libgcc/gthr-os2.h
index ac4f709..1d01f12 100644
--- a/libgcc/gthr-os2.h
+++ b/libgcc/gthr-os2.h
@@ -1,6 +1,7 @@
 /* Threads compatibily routines for libgcc2.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+   Contributed by KO Myung-Hun <komh@chollian.net>.

 This file is part of GNU CC.

@@ -33,6 +34,10 @@ Boston, MA 02111-1307, USA.  */
 #error "gthr-os2.h doesn't implement the _LIBOBJC mode!"
 #endif 

+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define __GTHREADS 1

 /* OS/2 threads specific definitions */
@@ -46,21 +51,24 @@ Boston, MA 02111-1307, USA.  */
 #include <InnoTekLIBC/backend.h>

 typedef int __gthread_key_t;
+
 typedef struct 
 {
   signed char volatile done;
   signed char volatile started;
 } __gthread_once_t;
-typedef _fmutex __gthread_mutex_t;
+
 typedef struct {
-  long depth;
-  uint32_t owner;
-  _fmutex actual;
-} __gthread_recursive_mutex_t;
+  int recursive;
+  unsigned long mtx;
+  _fmutex static_lock;
+} __gthread_mutex_t, __gthread_recursive_mutex_t;

 #define __GTHREAD_ONCE_INIT        { 0, 0 }
-#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
+#define __GTHREAD_MUTEX_INIT    { 0, 0, _FMUTEX_INITIALIZER }
 #define __GTHREAD_MUTEX_INIT_FUNCTION  __gthread_mutex_init_function
+#define __GTHREAD_RECURSIVE_MUTEX_INIT { 1, 0, _FMUTEX_INITIALIZER }
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function

 static inline int
 __gthread_active_p (void)
@@ -95,99 +103,70 @@ __gthread_once (__gthread_once_t *once, void (*func) (void))
   return 0;
 }

+extern void __gthread_os2_mutex_init (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_destroy (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_lock (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_trylock (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_unlock (__gthread_mutex_t *, int);
+
 static inline void
 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
 {
-  _fmutex_create (mutex, 0);
+  __gthread_os2_mutex_init (mutex, 0);
 }

 static inline int
 __gthread_mutex_destroy (__gthread_mutex_t *mutex )
 {
-  return 0;
+  return __gthread_os2_mutex_destroy (mutex, 0);
 }

 static inline int
 __gthread_mutex_lock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_request (mutex, _FMR_IGNINT);
+  return __gthread_os2_mutex_lock (mutex, 0);
 }

 static inline int
 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_request (mutex, _FMR_IGNINT | _FMR_NOWAIT);
+  return __gthread_os2_mutex_trylock (mutex, 0);
 }

 static inline int
 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_release (mutex);
+  return __gthread_os2_mutex_unlock (mutex, 0);
 }

-static inline int
+static inline void
 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
 {
-  mutex->depth = 0;
-  mutex->owner = fibGetTidPid();
-  return _fmutex_create (&mutex->actual, 0);
+  __gthread_os2_mutex_init (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      uint32_t me = fibGetTidPid();
-
-      if (mutex->owner != me)
-   {
-     __gthread_mutex_lock(&mutex->actual);
-     mutex->owner = me;
-   }
-
-      mutex->depth++;
-    }
-  return 0;
+  return __gthread_os2_mutex_destroy (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      uint32_t me = fibGetTidPid();
-
-      if (mutex->owner != me)
-   {
-     if (__gthread_mutex_trylock(&mutex->actual))
-       return 1;
-     mutex->owner = me;
-   }
-
-      mutex->depth++;
-    }
-  return 0;
+  return __gthread_os2_mutex_lock (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      if (--mutex->depth == 0)
-   {
-      mutex->owner = fibGetTidPid();
-      __gthread_mutex_unlock(&mutex->actual);
-   }
-    }
-  return 0;
+  return __gthread_os2_mutex_trylock (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
 {
-  return 0;
+  return __gthread_os2_mutex_unlock (mutex, 1);
 }

 static inline int
@@ -231,4 +210,145 @@ __gthread_setspecific (__gthread_key_t key, const void *ptr)
   return 0;
 }

+#define __GTHREAD_HAS_COND 1
+
+typedef struct {
+  unsigned long ev;
+  unsigned volatile waiters;
+  _fmutex static_lock;
+} __gthread_cond_t;
+
+#define __GTHREAD_COND_INIT { 0, 0, _FMUTEX_INITIALIZER }
+#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
+
+extern void __gthread_os2_cond_init (__gthread_cond_t *);
+extern int __gthread_os2_cond_destroy (__gthread_cond_t *);
+extern int __gthread_os2_cond_broadcast (__gthread_cond_t *);
+extern int __gthread_os2_cond_wait (__gthread_cond_t *, __gthread_mutex_t *);
+extern int __gthread_os2_cond_wait_recursive (__gthread_cond_t *,
+                                              __gthread_recursive_mutex_t *);
+
+static inline void
+__gthread_cond_init_function (__gthread_cond_t *cond)
+{
+  __gthread_os2_cond_init (cond);
+}
+
+static inline int
+__gthread_cond_destroy (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_destroy (cond);
+}
+
+static inline int
+__gthread_cond_broadcast (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_broadcast (cond);
+}
+
+static inline int
+__gthread_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait (cond, mutex);
+}
+
+static inline int
+__gthread_cond_wait_recursive (__gthread_cond_t *cond,
+                               __gthread_recursive_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_recursive (cond, mutex);
+}
+
+#define __GTHREADS_CXX0X 1
+
+#include <time.h>
+
+typedef int __gthread_t;
+
+typedef struct timespec __gthread_time_t;
+
+extern int __gthread_os2_create (__gthread_t *, void *(*) (void*), void *);
+extern int __gthread_os2_join (__gthread_t, void **);
+extern int __gthread_os2_detach (__gthread_t);
+extern int __gthread_os2_equal (__gthread_t, __gthread_t);
+extern int __gthread_os2_self (void);
+extern int __gthread_os2_yield (void);
+extern int __gthread_os2_mutex_timedlock (__gthread_mutex_t *,
+                                          const __gthread_time_t *);
+extern int
+  __gthread_os2_recursive_mutex_timedlock (__gthread_recursive_mutex_t *,
+                                           const __gthread_time_t *);
+extern int __gthread_os2_cond_signal (__gthread_cond_t *);
+extern int __gthread_os2_cond_timedwait (__gthread_cond_t *,
+                                         __gthread_mutex_t *,
+                                         const __gthread_time_t *);
+
+static inline int
+__gthread_create (__gthread_t *thread, void *(*func) (void*), void *args)
+{
+  return __gthread_os2_create (thread, func, args);
+}
+
+static inline int
+__gthread_join (__gthread_t thread, void **value_ptr)
+{
+  return __gthread_os2_join (thread, value_ptr);
+}
+
+static inline int
+__gthread_detach (__gthread_t thread)
+{
+  return __gthread_os2_detach (thread);
+}
+
+/* Compare threads. Return non-zero if equal, otherwise 0.  */
+static inline int
+__gthread_equal (__gthread_t t1, __gthread_t t2)
+{
+  return __gthread_os2_equal (t1, t2);
+}
+
+static inline __gthread_t
+__gthread_self (void)
+{
+  return __gthread_os2_self ();
+}
+
+static inline int
+__gthread_yield (void)
+{
+  return __gthread_os2_yield ();
+}
+
+static inline int
+__gthread_mutex_timedlock (__gthread_mutex_t *mutex,
+                           const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_timedlock (mutex, abs_timeout);
+}
+
+static inline int
+__gthread_recursive_mutex_timedlock (__gthread_recursive_mutex_t *mutex,
+                                     const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_recursive_mutex_timedlock (mutex, abs_timeout);
+}
+
+static inline int
+__gthread_cond_signal (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_signal (cond);
+}
+
+static inline int
+__gthread_cond_timedwait (__gthread_cond_t *cond, __gthread_mutex_t *mutex,
+                          const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_cond_timedwait (cond, mutex, abs_timeout);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* not __gthr_os2_h */
-- 
2.7.0
komh commented 8 years ago

Updated.

From 0be15a4365cef82696c00463ebabc2eb214e9d81 Mon Sep 17 00:00:00 2001
From: KO Myung-Hun <komh@chollian.net>
Date: Sun, 31 Jan 2016 21:31:33 +0900
Subject: [PATCH] OS/2: add C++11 thread support

    modified:   libgcc/config.host
    modified:   libgcc/config/i386/libgcc-emx.ver
    new file:   libgcc/config/i386/t-gthr-os2
    new file:   libgcc/gthr-os2.c
    modified:   libgcc/gthr-os2.h
---
 libgcc/config.host                |   5 +
 libgcc/config/i386/libgcc-emx.ver |  26 +++
 libgcc/config/i386/t-gthr-os2     |   2 +
 libgcc/gthr-os2.c                 | 442 ++++++++++++++++++++++++++++++++++++++
 libgcc/gthr-os2.h                 | 234 +++++++++++++++-----
 5 files changed, 652 insertions(+), 57 deletions(-)
 create mode 100644 libgcc/config/i386/t-gthr-os2
 create mode 100644 libgcc/gthr-os2.c

diff --git a/libgcc/config.host b/libgcc/config.host
index 9f021a1..c92fdb9 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -686,6 +686,11 @@ i[34567]86-*-interix[3-9]*)
    ;;
 i*86-pc-*emx)      # i?86 running OS/2
    tmake_file="$tmake_file i386/t-emx"
+   case ${target_thread_file} in
+     os2)
+       tmake_file="$tmake_file i386/t-gthr-os2"
+       ;;
+   esac
    extra_parts="$extra_parts emx-ctordtor.o"
    host_exeext=.exe
    ;;
diff --git a/libgcc/config/i386/libgcc-emx.ver b/libgcc/config/i386/libgcc-emx.ver
index 03ba5ec..b8fecac 100644
--- a/libgcc/config/i386/libgcc-emx.ver
+++ b/libgcc/config/i386/libgcc-emx.ver
@@ -19,3 +19,29 @@
 # Export custom EMX/KLIBC build symbols

 __chkstk_ms
+
+# __GTHREADS
+__gthread_os2_mutex_init
+__gthread_os2_mutex_destroy
+__gthread_os2_mutex_lock
+__gthread_os2_mutex_trylock
+__gthread_os2_mutex_unlock
+
+# __GTHREAD_HAS_COND
+__gthread_os2_cond_init
+__gthread_os2_cond_destroy
+__gthread_os2_cond_broadcast
+__gthread_os2_cond_wait
+__gthread_os2_cond_wait_recursive
+
+# __GTHREADS_CXX0X
+__gthread_os2_create
+__gthread_os2_join
+__gthread_os2_detach
+__gthread_os2_equal
+__gthread_os2_self
+__gthread_os2_yield
+__gthread_os2_mutex_timedlock
+__gthread_os2_recursive_mutex_timedlock
+__gthread_os2_cond_signal
+__gthread_os2_cond_timedwait
diff --git a/libgcc/config/i386/t-gthr-os2 b/libgcc/config/i386/t-gthr-os2
new file mode 100644
index 0000000..4cf4e55
--- /dev/null
+++ b/libgcc/config/i386/t-gthr-os2
@@ -0,0 +1,2 @@
+# We hide calls to OS/2 APIs needed for OS/2 thread support here:
+LIB2ADD = $(srcdir)/gthr-os2.c
diff --git a/libgcc/gthr-os2.c b/libgcc/gthr-os2.c
new file mode 100644
index 0000000..a387113
--- /dev/null
+++ b/libgcc/gthr-os2.c
@@ -0,0 +1,442 @@
+/* Threads compatibily routines for libgcc2.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+   Contributed by KO Myung-Hun <komh@chollian.net>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#define INCL_DOS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/builtin.h>
+#include <sys/fmutex.h>
+#include <sys/time.h>
+
+#include "gthr-os2.h"
+
+void
+__gthread_os2_mutex_init (__gthread_mutex_t *mutex, int recursive)
+{
+  mutex->recursive = recursive;
+  DosCreateMutexSem (NULL, (PHMTX) &mutex->mtx, 0, FALSE);
+}
+
+int
+__gthread_os2_mutex_destroy (__gthread_mutex_t *mutex, int recursive)
+{
+  if (mutex->recursive != recursive)
+    return 1;
+
+  return DosCloseMutexSem ((HMTX) mutex->mtx);
+}
+
+static int
+__gthread_os2_mutex_lock_common (__gthread_mutex_t *mutex, int recursive,
+                                 ULONG ulTimeout)
+{
+  PID pid;
+  TID tid;
+  ULONG ulCount;
+
+  if (mutex->recursive != recursive)
+    return 1;
+
+  /* Initialize static mutex.  */
+  if ((HMTX) mutex->mtx == NULLHANDLE)
+    {
+      /* FIXME: resource leaks.  */
+      _fmutex_request (&mutex->static_lock, _FMR_IGNINT);
+      if ((HMTX) mutex->mtx == NULLHANDLE)
+        __gthread_os2_mutex_init (mutex, recursive);
+      _fmutex_release (&mutex->static_lock);
+    }
+
+  if (DosRequestMutexSem ((HMTX) mutex->mtx, ulTimeout))
+    return 1;
+
+  DosQueryMutexSem ((HMTX) mutex->mtx, &pid, &tid, &ulCount);
+
+  /* non-recursive trylock ? */
+  if (!mutex->recursive && ulTimeout == SEM_IMMEDIATE_RETURN && ulCount > 1)
+    {
+      DosReleaseMutexSem ((HMTX) mutex->mtx);
+
+      return 1;
+    }
+
+  assert (!"Dead lock" || mutex->recursive || ulCount == 1);
+
+  return 0;
+}
+
+int
+__gthread_os2_mutex_lock (__gthread_mutex_t *mutex, int recursive)
+{
+  return __gthread_os2_mutex_lock_common (mutex, recursive,
+                                          SEM_INDEFINITE_WAIT);
+}
+
+int
+__gthread_os2_mutex_trylock (__gthread_mutex_t *mutex, int recursive)
+{
+  return __gthread_os2_mutex_lock_common (mutex, recursive,
+                                          SEM_IMMEDIATE_RETURN);
+}
+
+int
+__gthread_os2_mutex_unlock (__gthread_mutex_t *mutex, int recursive)
+{
+  if (mutex->recursive != recursive)
+    return 1;
+
+  return DosReleaseMutexSem ((HMTX) mutex->mtx);
+}
+
+#ifndef DCE_POSTONE
+#define DCE_POSTONE 0x0800  /* Wake up only one waiter and auto reset */
+#endif
+
+void
+__gthread_os2_cond_init (__gthread_cond_t *cond)
+{
+  DosCreateEventSem (NULL, (PHEV) &cond->ev, DCE_POSTONE, FALSE);
+  cond->waiters = 0;
+}
+
+int
+__gthread_os2_cond_destroy (__gthread_cond_t *cond)
+{
+  return DosCloseEventSem ((HEV) cond->ev);
+}
+
+static void
+__gthread_os2_static_cond_init (__gthread_cond_t *cond)
+{
+  /* FIXME: resource leaks */
+  _fmutex_request (&cond->static_lock, _FMR_IGNINT);
+  if ((HEV) cond->ev == NULLHANDLE)
+     __gthread_os2_cond_init (cond);
+  _fmutex_release (&cond->static_lock);
+}
+
+int
+__gthread_os2_cond_broadcast (__gthread_cond_t *cond)
+{
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  while (!__atomic_cmpxchg32 (&cond->waiters, 0, 0))
+    {
+      if (DosPostEventSem ((HEV) cond->ev))
+        DosSleep (1);
+    }
+
+  return 0;
+}
+
+static int
+__gthread_os2_cond_wait_common (__gthread_cond_t *cond,
+                                __gthread_mutex_t *mutex,
+                                int recursive, ULONG ulTimeout)
+{
+  APIRET rc;
+
+  if (mutex->recursive != recursive)
+    return 1;
+
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  __atomic_increment (&cond->waiters);
+
+  __gthread_os2_mutex_unlock (mutex, recursive);
+
+  rc = DosWaitEventSem ((HEV) cond->ev, ulTimeout);
+
+  __atomic_decrement (&cond->waiters);
+
+  __gthread_os2_mutex_lock (mutex, recursive);
+
+  return rc;
+}
+
+int
+__gthread_os2_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 0, SEM_INDEFINITE_WAIT);
+}
+
+int
+__gthread_os2_cond_wait_recursive (__gthread_cond_t *cond,
+                                   __gthread_recursive_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 1, SEM_INDEFINITE_WAIT);
+}
+
+typedef struct __gthread_os2_s __gthread_os2_t;
+
+struct __gthread_os2_s {
+  __gthread_t tid;
+  void *(*func) (void*);
+  void *args;
+  void *result;
+  HEV hevQuit;
+  HEV hevDone;
+  int detached;
+  __gthread_os2_t *next;
+};
+
+static __gthread_os2_t main_thread =
+  { 1, NULL, NULL, NULL, NULLHANDLE, NULLHANDLE, 0, NULL };
+
+static __gthread_os2_t *__gthread_os2_thread_start = &main_thread;
+
+static __gthread_os2_t *
+__gthread_os2_thread_new (void *(*func) (void*), void *args)
+{
+  __gthread_os2_t *new_thread;
+
+  new_thread = calloc (1, sizeof (*new_thread));
+  if (new_thread)
+    {
+      new_thread->func = func;
+      new_thread->args = args;
+      DosCreateEventSem (NULL, &new_thread->hevQuit, 0, FALSE);
+      DosCreateEventSem (NULL, &new_thread->hevDone, 0, FALSE);
+    }
+
+  return new_thread;
+}
+
+static void
+__gthread_os2_thread_free (__gthread_os2_t *thread)
+{
+  if (thread == &main_thread)
+    return;
+
+  DosCloseEventSem (thread->hevQuit);
+  DosCloseEventSem (thread->hevDone);
+
+  free (thread);
+}
+
+static __gthread_os2_t *
+__gthread_os2_thread_find (__gthread_t tid)
+{
+  __gthread_os2_t *thread = __gthread_os2_thread_start;
+
+  while (thread && thread->tid != tid)
+    thread = thread->next;
+
+  return thread;
+}
+
+static void
+__gthread_os2_thread_add (__gthread_os2_t *thread, __gthread_t tid)
+{
+  thread->tid = tid;
+  thread->next = __gthread_os2_thread_start;
+
+  __gthread_os2_thread_start = thread;
+}
+
+static void
+__gthread_os2_thread_del (__gthread_os2_t *thread)
+{
+  if (thread == &main_thread)
+    return;
+
+  if (thread == __gthread_os2_thread_start)
+    __gthread_os2_thread_start = thread->next;
+  else
+    {
+      __gthread_os2_t *prev;
+
+      for (prev = __gthread_os2_thread_start; prev->next != thread;
+           prev = prev->next)
+        /* nothing */;
+
+      prev->next = thread->next;
+    }
+
+  __gthread_os2_thread_free (thread);
+}
+
+static void thread_entry (void *args)
+{
+  __gthread_os2_t *th = (__gthread_os2_t *)args;
+  int detached;
+
+  th->result = th->func(th->args);
+  DosWaitEventSem (th->hevQuit, SEM_INDEFINITE_WAIT);
+
+  detached = th->detached;
+
+  DosPostEventSem (th->hevDone);
+
+  if (detached)
+    __gthread_os2_thread_del (th);
+}
+
+int
+__gthread_os2_create (__gthread_t *thread, void *(*func) (void*), void *args)
+{
+  __gthread_os2_t *th;
+  int tid;
+
+  th = __gthread_os2_thread_new (func, args);
+  if (!th)
+    return ENOMEM;
+
+  tid = _beginthread (thread_entry, NULL, 1024 * 1024, th);
+  if (tid == -1)
+    {
+      __gthread_os2_thread_free (th);
+
+      return 1;
+    }
+
+  __gthread_os2_thread_add (th, tid);
+
+  *thread = tid;
+
+  return 0;
+}
+
+int
+__gthread_os2_join (__gthread_t thread, void **value_ptr)
+{
+  __gthread_os2_t *th;
+
+  th = __gthread_os2_thread_find (thread);
+
+  if (!th || th->detached)
+    return 1;
+
+  DosPostEventSem (th->hevQuit);
+
+  if (DosWaitEventSem (th->hevDone, SEM_INDEFINITE_WAIT))
+    return 1;
+
+  if (value_ptr)
+    *value_ptr = th->result;
+
+  __gthread_os2_thread_del (th);
+
+  return 0;
+}
+
+int
+__gthread_os2_detach (__gthread_t thread)
+{
+  __gthread_os2_t *th;
+
+  th = __gthread_os2_thread_find (thread);
+  if (!th)
+    return 1;
+
+  th->detached = 1;
+
+  DosPostEventSem (th->hevQuit);
+
+  return 0;
+}
+
+/* Compare threads. Return non-zero if same, otherwise 0.  */
+int
+__gthread_os2_equal (__gthread_t t1, __gthread_t t2)
+{
+  return t1 == t2;
+}
+
+__gthread_t
+__gthread_os2_self (void)
+{
+  return _gettid();
+}
+
+int
+__gthread_os2_yield (void)
+{
+  DosSleep (0);
+
+  return 0;
+}
+
+static ULONG
+__gthread_os2_abs2rem (const __gthread_time_t *abs_timeout)
+{
+  struct timeval tv;
+  ULONG ulNow;
+  ULONG ulDeadline;
+  ULONG ulRemain;
+
+  gettimeofday (&tv, NULL);
+  ulNow = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+  ulDeadline = abs_timeout->tv_sec * 1000 + abs_timeout->tv_nsec / 1000000UL;
+  ulRemain = (ulDeadline > ulNow) ? (ulDeadline - ulNow) : 0;
+
+  return ulRemain;
+}
+
+int
+__gthread_os2_mutex_timedlock (__gthread_mutex_t *mutex,
+                               const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_lock_common (mutex, 0,
+                                          __gthread_os2_abs2rem (abs_timeout));
+}
+
+int
+__gthread_os2_recursive_mutex_timedlock (__gthread_recursive_mutex_t *mutex,
+                                         const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_lock_common (mutex, 1,
+                                          __gthread_os2_abs2rem (abs_timeout));
+}
+
+int
+__gthread_os2_cond_signal (__gthread_cond_t *cond)
+{
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  if (!__atomic_cmpxchg32 (&cond->waiters, 0, 0))
+    DosPostEventSem ((HEV) cond->ev);
+
+  return 0;
+}
+
+int
+__gthread_os2_cond_timedwait (__gthread_cond_t *cond, __gthread_mutex_t *mutex,
+                              const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 0,
+                                         __gthread_os2_abs2rem (abs_timeout));
+}
diff --git a/libgcc/gthr-os2.h b/libgcc/gthr-os2.h
index ac4f709..1d01f12 100644
--- a/libgcc/gthr-os2.h
+++ b/libgcc/gthr-os2.h
@@ -1,6 +1,7 @@
 /* Threads compatibily routines for libgcc2.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+   Contributed by KO Myung-Hun <komh@chollian.net>.

 This file is part of GNU CC.

@@ -33,6 +34,10 @@ Boston, MA 02111-1307, USA.  */
 #error "gthr-os2.h doesn't implement the _LIBOBJC mode!"
 #endif 

+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define __GTHREADS 1

 /* OS/2 threads specific definitions */
@@ -46,21 +51,24 @@ Boston, MA 02111-1307, USA.  */
 #include <InnoTekLIBC/backend.h>

 typedef int __gthread_key_t;
+
 typedef struct 
 {
   signed char volatile done;
   signed char volatile started;
 } __gthread_once_t;
-typedef _fmutex __gthread_mutex_t;
+
 typedef struct {
-  long depth;
-  uint32_t owner;
-  _fmutex actual;
-} __gthread_recursive_mutex_t;
+  int recursive;
+  unsigned long mtx;
+  _fmutex static_lock;
+} __gthread_mutex_t, __gthread_recursive_mutex_t;

 #define __GTHREAD_ONCE_INIT        { 0, 0 }
-#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
+#define __GTHREAD_MUTEX_INIT    { 0, 0, _FMUTEX_INITIALIZER }
 #define __GTHREAD_MUTEX_INIT_FUNCTION  __gthread_mutex_init_function
+#define __GTHREAD_RECURSIVE_MUTEX_INIT { 1, 0, _FMUTEX_INITIALIZER }
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function

 static inline int
 __gthread_active_p (void)
@@ -95,99 +103,70 @@ __gthread_once (__gthread_once_t *once, void (*func) (void))
   return 0;
 }

+extern void __gthread_os2_mutex_init (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_destroy (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_lock (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_trylock (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_unlock (__gthread_mutex_t *, int);
+
 static inline void
 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
 {
-  _fmutex_create (mutex, 0);
+  __gthread_os2_mutex_init (mutex, 0);
 }

 static inline int
 __gthread_mutex_destroy (__gthread_mutex_t *mutex )
 {
-  return 0;
+  return __gthread_os2_mutex_destroy (mutex, 0);
 }

 static inline int
 __gthread_mutex_lock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_request (mutex, _FMR_IGNINT);
+  return __gthread_os2_mutex_lock (mutex, 0);
 }

 static inline int
 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_request (mutex, _FMR_IGNINT | _FMR_NOWAIT);
+  return __gthread_os2_mutex_trylock (mutex, 0);
 }

 static inline int
 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_release (mutex);
+  return __gthread_os2_mutex_unlock (mutex, 0);
 }

-static inline int
+static inline void
 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
 {
-  mutex->depth = 0;
-  mutex->owner = fibGetTidPid();
-  return _fmutex_create (&mutex->actual, 0);
+  __gthread_os2_mutex_init (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      uint32_t me = fibGetTidPid();
-
-      if (mutex->owner != me)
-   {
-     __gthread_mutex_lock(&mutex->actual);
-     mutex->owner = me;
-   }
-
-      mutex->depth++;
-    }
-  return 0;
+  return __gthread_os2_mutex_destroy (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      uint32_t me = fibGetTidPid();
-
-      if (mutex->owner != me)
-   {
-     if (__gthread_mutex_trylock(&mutex->actual))
-       return 1;
-     mutex->owner = me;
-   }
-
-      mutex->depth++;
-    }
-  return 0;
+  return __gthread_os2_mutex_lock (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      if (--mutex->depth == 0)
-   {
-      mutex->owner = fibGetTidPid();
-      __gthread_mutex_unlock(&mutex->actual);
-   }
-    }
-  return 0;
+  return __gthread_os2_mutex_trylock (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
 {
-  return 0;
+  return __gthread_os2_mutex_unlock (mutex, 1);
 }

 static inline int
@@ -231,4 +210,145 @@ __gthread_setspecific (__gthread_key_t key, const void *ptr)
   return 0;
 }

+#define __GTHREAD_HAS_COND 1
+
+typedef struct {
+  unsigned long ev;
+  unsigned volatile waiters;
+  _fmutex static_lock;
+} __gthread_cond_t;
+
+#define __GTHREAD_COND_INIT { 0, 0, _FMUTEX_INITIALIZER }
+#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
+
+extern void __gthread_os2_cond_init (__gthread_cond_t *);
+extern int __gthread_os2_cond_destroy (__gthread_cond_t *);
+extern int __gthread_os2_cond_broadcast (__gthread_cond_t *);
+extern int __gthread_os2_cond_wait (__gthread_cond_t *, __gthread_mutex_t *);
+extern int __gthread_os2_cond_wait_recursive (__gthread_cond_t *,
+                                              __gthread_recursive_mutex_t *);
+
+static inline void
+__gthread_cond_init_function (__gthread_cond_t *cond)
+{
+  __gthread_os2_cond_init (cond);
+}
+
+static inline int
+__gthread_cond_destroy (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_destroy (cond);
+}
+
+static inline int
+__gthread_cond_broadcast (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_broadcast (cond);
+}
+
+static inline int
+__gthread_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait (cond, mutex);
+}
+
+static inline int
+__gthread_cond_wait_recursive (__gthread_cond_t *cond,
+                               __gthread_recursive_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_recursive (cond, mutex);
+}
+
+#define __GTHREADS_CXX0X 1
+
+#include <time.h>
+
+typedef int __gthread_t;
+
+typedef struct timespec __gthread_time_t;
+
+extern int __gthread_os2_create (__gthread_t *, void *(*) (void*), void *);
+extern int __gthread_os2_join (__gthread_t, void **);
+extern int __gthread_os2_detach (__gthread_t);
+extern int __gthread_os2_equal (__gthread_t, __gthread_t);
+extern int __gthread_os2_self (void);
+extern int __gthread_os2_yield (void);
+extern int __gthread_os2_mutex_timedlock (__gthread_mutex_t *,
+                                          const __gthread_time_t *);
+extern int
+  __gthread_os2_recursive_mutex_timedlock (__gthread_recursive_mutex_t *,
+                                           const __gthread_time_t *);
+extern int __gthread_os2_cond_signal (__gthread_cond_t *);
+extern int __gthread_os2_cond_timedwait (__gthread_cond_t *,
+                                         __gthread_mutex_t *,
+                                         const __gthread_time_t *);
+
+static inline int
+__gthread_create (__gthread_t *thread, void *(*func) (void*), void *args)
+{
+  return __gthread_os2_create (thread, func, args);
+}
+
+static inline int
+__gthread_join (__gthread_t thread, void **value_ptr)
+{
+  return __gthread_os2_join (thread, value_ptr);
+}
+
+static inline int
+__gthread_detach (__gthread_t thread)
+{
+  return __gthread_os2_detach (thread);
+}
+
+/* Compare threads. Return non-zero if equal, otherwise 0.  */
+static inline int
+__gthread_equal (__gthread_t t1, __gthread_t t2)
+{
+  return __gthread_os2_equal (t1, t2);
+}
+
+static inline __gthread_t
+__gthread_self (void)
+{
+  return __gthread_os2_self ();
+}
+
+static inline int
+__gthread_yield (void)
+{
+  return __gthread_os2_yield ();
+}
+
+static inline int
+__gthread_mutex_timedlock (__gthread_mutex_t *mutex,
+                           const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_timedlock (mutex, abs_timeout);
+}
+
+static inline int
+__gthread_recursive_mutex_timedlock (__gthread_recursive_mutex_t *mutex,
+                                     const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_recursive_mutex_timedlock (mutex, abs_timeout);
+}
+
+static inline int
+__gthread_cond_signal (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_signal (cond);
+}
+
+static inline int
+__gthread_cond_timedwait (__gthread_cond_t *cond, __gthread_mutex_t *mutex,
+                          const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_cond_timedwait (cond, mutex, abs_timeout);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* not __gthr_os2_h */
-- 
2.7.0
psmedley commented 8 years ago

Hi KO!

Thanks for this. Is the base based on current git (ie gcc 4.9.x) or off of the 5.3.x code?

Cheers,

Paul

On 13/02/16 22:43, KO Myung-Hun wrote:

Updated.

| From 0be15a4365cef82696c00463ebabc2eb214e9d81 Mon Sep 17 00:00:00 2001 From: KO Myung-Hun komh@chollian.net Date: Sun, 31 Jan 2016 21:31:33 +0900 Subject: [PATCH] OS/2: add C++11 thread support modified: libgcc/config.host modified: libgcc/config/i386/libgcc-emx.ver new file: libgcc/config/i386/t-gthr-os2 new file: libgcc/gthr-os2.c modified: libgcc/gthr-os2.h --- libgcc/config.host | 5 + libgcc/config/i386/libgcc-emx.ver | 26 +++ libgcc/config/i386/t-gthr-os2 | 2 + libgcc/gthr-os2.c | 442 ++++++++++++++++++++++++++++++++++++++ libgcc/gthr-os2.h | 234 +++++++++++++++----- 5 files changed, 652 insertions(+), 57 deletions(-) create mode 100644 libgcc/config/i386/t-gthr-os2 create mode 100644 libgcc/gthr-os2.c diff --git a/libgcc/config.host b/libgcc/config.host index 9f021a1..c92fdb9 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -686,6 +686,11 @@ i[34567]86--interix[3-9]) ;; i_86-pc-_emx) # i?86 running OS/2 tmake_file="$tmake_file i386/t-emx" + case ${target_thread_file} in

  • os2) + tmake_file="$tmake_file i386/t-gthr-os2" + ;; + esac extra_parts="$extra_parts emx-ctordtor.o" host_exeext=.exe ;; diff --git a/libgcc/config/i386/libgcc-emx.ver b/libgcc/config/i386/libgcc-emx.ver index 03ba5ec..b8fecac 100644 --- a/libgcc/config/i386/libgcc-emx.ver +++ b/libgcc/config/i386/libgcc-emx.ver @@ -19,3 +19,29 @@ # Export custom EMX/KLIBC build symbols chkstk_ms + +# GTHREADS +gthread_os2_mutex_init +gthread_os2_mutex_destroy +gthread_os2_mutex_lock +__gthread_os2_mutex_trylock +gthread_os2_mutex_unlock + +# GTHREAD_HAS_COND +gthread_os2_cond_init +gthread_os2_cond_destroy +__gthread_os2_cond_broadcast +gthread_os2_cond_wait +gthread_os2_cond_wait_recursive + +# GTHREADS_CXX0X +gthread_os2_create +gthread_os2_join +gthread_os2_detach +gthread_os2_equal +gthread_os2_self +gthread_os2_yield +gthread_os2_mutex_timedlock +gthread_os2_recursive_mutex_timedlock +gthread_os2_cond_signal +gthread_os2_condtimedwait diff --git a/libgcc/config/i386/t-gthr-os2 b/libgcc/config/i386/t-gthr-os2 new file mode 100644 index 0000000..4cf4e55 --- /dev/null +++ b/libgcc/config/i386/t-gthr-os2 @@ -0,0 +1,2 @@ +# We hide calls to OS/2 APIs needed for OS/2 thread support here: +LIB2ADD = $(srcdir)/gthr-os2.c diff --git a/libgcc/gthr-os2.c b/libgcc/gthr-os2.c new file mode 100644 index 0000000..a387113 --- /dev/null +++ b/libgcc/gthr-os2.c @@ -0,0 +1,442 @@ +/* Threads compatibily routines for libgcc2. / +/ Compile this one with gcc. / +/ Copyright (C) 1997-2016 Free Software Foundation, Inc. + Contributed by KO Myung-Hun komh@chollian.net. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. / + +/_ As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License.
  • This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. _/ + +#define INCL_DOS +#define INCL_DOSERRORS +#include + +#include +#include + +#include +#include +#include + +#include "gthr-os2.h" + +void +__gthread_os2_mutex_init (__gthread_mutex_t *mutex, int recursive) +{ + mutex->recursive = recursive; + DosCreateMutexSem (NULL, (PHMTX) &mutex->mtx, 0, FALSE); +} + +int +__gthread_os2_mutex_destroy (__gthread_mutex_t *mutex, int recursive) +{ + if (mutex->recursive != recursive) + return 1; + + return DosCloseMutexSem ((HMTX) mutex->mtx); +} + +static int +__gthread_os2_mutex_lock_common (__gthread_mutex_t *mutex, int recursive, + ULONG ulTimeout) +{ + PID pid; + TID tid; + ULONG ulCount; + + if (mutex->recursive != recursive) + return 1; + + /_ Initialize static mutex. _/ + if ((HMTX) mutex->mtx == NULLHANDLE) + { + /_ FIXME: resource leaks. _/ + _fmutex_request (&mutex->static_lock, _FMR_IGNINT); + if ((HMTX) mutex->mtx == NULLHANDLE) + __gthread_os2_mutex_init (mutex, recursive); + _fmutex_release (&mutex->static_lock); + } + + if (DosRequestMutexSem ((HMTX) mutex->mtx, ulTimeout)) + return 1; + + DosQueryMutexSem ((HMTX) mutex->mtx, &pid, &tid, &ulCount); + + /_ non-recursive trylock ? _/ + if (!mutex->recursive && ulTimeout == SEM_IMMEDIATE_RETURN && ulCount > 1) + { + DosReleaseMutexSem ((HMTX) mutex->mtx); + + return 1; + } + + assert (!"Dead lock" || mutex->recursive || ulCount == 1); + + return 0; +} + +int +__gthread_os2_mutex_lock (__gthread_mutex_t *mutex, int recursive) +{ + return __gthread_os2_mutex_lock_common (mutex, recursive, + SEM_INDEFINITE_WAIT); +} + +int +__gthread_os2_mutex_trylock (__gthread_mutex_t *mutex, int recursive) +{ + return __gthread_os2_mutex_lock_common (mutex, recursive, + SEM_IMMEDIATE_RETURN); +} + +int +__gthread_os2_mutex_unlock (__gthread_mutex_t *mutex, int recursive) +{ + if (mutex->recursive != recursive) + return 1; + + return DosReleaseMutexSem ((HMTX) mutex->mtx); +} + +#ifndef DCE_POSTONE +#define DCE_POSTONE 0x0800 /_ Wake up only one waiter and auto reset _/ +#endif + +void +__gthread_os2_cond_init (__gthread_cond_t *cond) +{ + DosCreateEventSem (NULL, (PHEV) &cond->ev, DCE_POSTONE, FALSE); + cond->waiters = 0; +} + +int +__gthread_os2_cond_destroy (__gthread_cond_t *cond) +{ + return DosCloseEventSem ((HEV) cond->ev); +} + +static void +__gthread_os2_static_cond_init (__gthread_cond_t *cond) +{ + /_ FIXME: resource leaks */ + _fmutex_request (&cond->static_lock, _FMR_IGNINT); + if ((HEV) cond->ev == NULLHANDLE) + __gthread_os2_cond_init (cond); + _fmutex_release (&cond->static_lock); +} + +int +__gthread_os2_cond_broadcast (__gthread_cond_t *cond) +{ + if ((HEV) cond->ev == NULLHANDLE) + __gthread_os2_static_cond_init (cond); + + while (!__atomic_cmpxchg32 (&cond->waiters, 0, 0)) + { + if (DosPostEventSem ((HEV) cond->ev)) + DosSleep (1); + } + + return 0; +}
  • +static int +gthread_os2_cond_wait_common (gthread_cond_t _cond, + gthread_mutex_t *mutex, + int recursive, ULONG ulTimeout) +{ + APIRET rc; + + if (mutex->recursive != recursive) + return 1; + + if ((HEV) cond->ev == NULLHANDLE) + gthread_os2_static_cond_init (cond); + + atomic_increment (&cond->waiters); + + __gthread_os2_mutex_unlock (mutex, recursive); + + rc = DosWaitEventSem ((HEV) cond->ev, ulTimeout); + + atomic_decrement (&cond->waiters); + + gthread_os2_mutex_lock (mutex, recursive); + + return rc; +} + +int +__gthread_os2_cond_wait (gthread_cond_t cond, __gthread_mutex_t mutex) +{ + return gthread_os2_cond_wait_common (cond, mutex, 0, SEM_INDEFINITE_WAIT); +} + +int +gthread_os2_cond_wait_recursive (gthread_cond_t *cond, + gthread_recursive_mutex_t mutex) +{ + return gthread_os2_cond_wait_common (cond, mutex, 1, SEM_INDEFINITE_WAIT); +} + +typedef struct gthread_os2_s gthread_os2_t; + +struct gthread_os2_s { + __gthread_t tid; + void (func) (void); + void args; + void result; + HEV hevQuit; + HEV hevDone; + int detached; + gthread_os2_t *next; +}; + +static gthread_os2_t main_thread = + { 1, NULL, NULL, NULL, NULLHANDLE, NULLHANDLE, 0, NULL }; + +static gthread_os2_t *gthread_os2_thread_start = &main_thread; + +static gthread_os2_t * +gthread_os2_thread_new (void (func) (void), void args) +{ + gthread_os2_t *new_thread; + + new_thread = calloc (1, sizeof (_new_thread)); + if (new_thread) + { + new_thread->func = func; + new_thread->args = args; + DosCreateEventSem (NULL, &new_thread->hevQuit, 0, FALSE); + DosCreateEventSem (NULL, &new_thread->hevDone, 0, FALSE); + } + + return new_thread; +} + +static void +gthread_os2_thread_free (gthread_os2_t thread) +{ + if (thread == &main_thread) + return; + + DosCloseEventSem (thread->hevQuit); + DosCloseEventSem (thread->hevDone); + + free (thread); +} + +static __gthread_os2_t \ +__gthread_os2_thread_find (gthread_t tid) +{ + gthread_os2_t *thread = gthread_os2_thread_start; + + while (thread && thread->tid != tid) + thread = thread->next; + + return thread; +} + +static void +__gthread_os2_thread_add (gthread_os2_t *thread, gthread_t tid) +{
  • thread->tid = tid; + thread->next = gthread_os2_thread_start; + + __gthread_os2_thread_start = thread; +} + +static void +gthread_os2_thread_del (gthread_os2_t *thread) +{ + if (thread == &main_thread) + return; + + if (thread == __gthread_os2_thread_start) + gthread_os2_thread_start = thread->next; + else + { + gthread_os2_t *prev; + + for (prev = gthread_os2_thread_start; prev->next != thread;
  • prev = prev->next) + /* nothing */; + + prev->next = thread->next; + }
  • + gthread_os2_thread_free (thread); +} + +static void thread_entry (void _args) +{ + gthread_os2_t *th = (gthread_os2_t *)args; + int detached; + + th->result = th->func(th->args); + DosWaitEventSem (th->hevQuit, SEM_INDEFINITE_WAIT); + + detached = th->detached; + + DosPostEventSem (th->hevDone); + + if (detached) + __gthread_os2_thread_del (th); +} + +int +gthread_os2_create (gthread_t thread, void (func) (void), void args) +{ + __gthread_os2_t th; + int tid; + + th = __gthread_os2_thread_new (func, args); + if (!th) + return ENOMEM; + + tid = _beginthread (thread_entry, NULL, 1024 * 1024, th); + if (tid == -1) + { + gthread_os2_thread_free (th); + + return 1; + } + + gthread_os2_thread_add (th, tid); + + thread = tid; + + return 0; +} + +int +gthread_os2_join (gthread_t thread, void _value_ptr) +{ + gthread_os2_t _th; + + th = gthread_os2_thread_find (thread); + + if (!th || th->detached) + return 1; + + DosPostEventSem (th->hevQuit); + + if (DosWaitEventSem (th->hevDone, SEM_INDEFINITE_WAIT)) + return 1; + + if (value_ptr) + *value_ptr = th->result; + + __gthread_os2_thread_del (th); + + return 0; +} + +int +gthread_os2_detach (gthread_t thread) +{ + gthread_os2_t *th; + + th = gthread_os2_threadfind (thread); + if (!th) + return 1; + + th->detached = 1; + + DosPostEventSem (th->hevQuit); + + return 0; +} + +/ Compare threads. Return non-zero if same, otherwise 0. */ +int +gthread_os2_equal (gthread_t t1, gthread_t t2) +{ + return t1 == t2; +} + +gthread_t +__gthread_os2_self (void) +{ + return _gettid(); +} + +int +gthread_os2_yield (void) +{ + DosSleep (0); + + return 0; +} + +static ULONG +gthread_os2_abs2rem (const gthread_time_t *abs_timeout) +{ + struct timeval tv; + ULONG ulNow; + ULONG ulDeadline;
  • ULONG ulRemain; + + gettimeofday (&tv, NULL); + ulNow = tv.tv_sec 1000 + tv.tv_usec / 1000; + ulDeadline = abs_timeout->tv_sec * 1000 + abs_timeout->tv_nsec / 1000000UL; + ulRemain = (ulDeadline > ulNow) ? (ulDeadline - ulNow) : 0; + + return ulRemain; +} + +int +gthread_os2_mutex_timedlock (__gthread_mutex_t _mutex, + const gthread_time_t abs_timeout) +{ + return gthread_os2_mutex_lock_common (mutex, 0, + gthread_os2_abs2rem (abs_timeout)); +} + +int +gthread_os2_recursive_mutex_timedlock (gthread_recursive_mutex_t mutex, + const __gthread_time_t abs_timeout) +{ + return gthread_os2_mutex_lock_common (mutex, 1, + gthread_os2_abs2rem (abs_timeout)); +} + +int +gthread_os2_cond_signal (gthread_cond_t *cond) +{ + if ((HEV) cond->ev == NULLHANDLE) + gthread_os2_static_cond_init (cond); + + if (!__atomic_cmpxchg32 (&cond->waiters, 0, 0)) + DosPostEventSem ((HEV) cond->ev); + + return 0; +} + +int +gthread_os2_cond_timedwait (gthread_cond_t *cond, gthread_mutex_t mutex, + const __gthread_time_t abs_timeout) +{ + return gthread_os2_cond_wait_common (cond, mutex, 0, + gthread_os2_abs2rem (abstimeout)); +} diff --git a/libgcc/gthr-os2.h b/libgcc/gthr-os2.h index ac4f709..1d01f12 100644 --- a/libgcc/gthr-os2.h +++ b/libgcc/gthr-os2.h @@ -1,6 +1,7 @@ / Threads compatibily routines for libgcc2. / / Compile this one with gcc. / -/ Copyright (C) 1997 Free Software Foundation, Inc. +/* Copyright (C) 1997-2016 Free Software Foundation, Inc. + Contributed by KO Myung-Hun komh@chollian.net. This file is part of GNU CC. @@ -33,6 +34,10 @@ Boston, MA 02111-1307, USA. _/ #error "gthr-os2.h doesn't implement the LIBOBJC mode!" #endif +#ifdef cplusplus +extern "C" { +#endif + #define GTHREADS 1 / OS/2 threads specific definitions _/ @@ -46,21 +51,24 @@ Boston, MA 02111-1307, USA. / #include <InnoTekLIBC/backend.h> typedef int gthread_key_t; + typedef struct { signed char volatile done; signed char volatile started; } gthread_once_t; -typedef _fmutex gthread_mutex_t; + typedef struct { - long depth; - uint32_t owner; - _fmutex actual; -} gthread_recursive_mutex_t; + int recursive; + unsigned long mtx; + _fmutex static_lock; +} gthread_mutex_t, gthread_recursive_mutex_t; #define GTHREAD_ONCE_INIT { 0, 0 } -#define GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION gthread_recursive_mutex_init_function +#define GTHREAD_MUTEX_INIT { 0, 0, _FMUTEX_INITIALIZER } #define GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function +#define GTHREAD_RECURSIVE_MUTEX_INIT { 1, 0, _FMUTEX_INITIALIZER } +#define GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION gthread_recursive_mutex_init_function static inline int gthread_active_p (void) @@ -95,99 +103,70 @@ gthread_once (__gthread_once_t once, void (_func) (void)) return 0; } +extern void gthread_os2_mutex_init (gthread_mutex_t *, int); +extern int gthread_os2_mutex_destroy (gthread_mutex_t , int); +extern int __gthread_os2_mutex_lock (__gthread_mutex_t , int); +extern int gthread_os2_mutex_trylock (gthread_mutex_t *, int); +extern int gthread_os2_mutex_unlock (gthread_mutex_t , int); + static inline void __gthread_mutex_init_function (__gthread_mutex_t mutex) { - _fmutex_create (mutex, 0); + __gthread_os2_mutex_init (mutex, 0); } static inline int gthread_mutex_destroy (gthread_mutex_t *mutex ) {
  • return 0; + return gthread_os2_mutex_destroy (mutex, 0); } static inline int gthread_mutex_lock (gthread_mutex_t *mutex) { - return _fmutex_request (mutex, _FMR_IGNINT); + return __gthread_os2_mutex_lock (mutex, 0); } static inline int gthread_mutex_trylock (gthread_mutex_t *mutex) { - return _fmutex_request (mutex, _FMR_IGNINT | _FMR_NOWAIT); + return gthread_os2_mutex_trylock (mutex, 0); } static inline int gthread_mutex_unlock (gthread_mutex_t mutex) { - return _fmutex_release (mutex); + return __gthread_os2_mutex_unlock (mutex, 0); } -static inline int +static inline void gthread_recursive_mutex_init_function (gthread_recursive_mutex_t mutex) { - mutex->depth = 0; - mutex->owner = fibGetTidPid(); - return _fmutex_create (&mutex->actual, 0); + gthread_os2_mutex_init (mutex, 1); } static inline int -__gthread_recursive_mutex_lock (gthread_recursive_mutex_t mutex) +__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t mutex) { - if (gthread_active_p ()) - { - uint32_t me = fibGetTidPid(); - - if (mutex->owner != me) - { - gthread_mutex_lock(&mutex->actual); - mutex->owner = me; - } - - mutex->depth++; - } - return 0; + return gthread_os2_mutex_destroy (mutex, 1); } static inline int -gthread_recursive_mutex_trylock (gthread_recursive_mutex_t *mutex) +__gthread_recursive_mutex_lock (gthread_recursive_mutex_t *mutex) { - if (__gthread_active_p ()) - { - uint32_t me = fibGetTidPid(); - - if (mutex->owner != me) - { - if (__gthread_mutex_trylock(&mutex->actual))
  • return 1; - mutex->owner = me; - } - - mutex->depth++; - } - return 0;
  • return gthread_os2_mutex_lock (mutex, 1); } static inline int -__gthread_recursive_mutex_unlock (gthread_recursive_mutex_t mutex) +__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t mutex) { - if (gthread_active_p ()) - { - if (--mutex->depth == 0) - { - mutex->owner = fibGetTidPid(); - gthread_mutex_unlock(&mutex->actual);
  • } - } - return 0; + return gthread_os2_mutex_trylock (mutex, 1); } static inline int -__gthread_recursive_mutex_destroy (gthread_recursive_mutex_t _mutex) +__gthread_recursive_mutex_unlock (gthread_recursive_mutex_t mutex) { - return 0; + return gthread_os2_mutex_unlock (mutex, 1); } static inline int @@ -231,4 +210,145 @@ __gthread_setspecific (gthread_key_t key, const void ptr) return 0; } +#define GTHREAD_HAS_COND 1 + +typedef struct { + unsigned long ev; + unsigned volatile waiters; + _fmutex static_lock; +} gthread_cond_t; + +#define GTHREAD_COND_INIT { 0, 0, _FMUTEX_INITIALIZER } +#define GTHREAD_COND_INIT_FUNCTION gthread_cond_init_function + +extern void __gthread_os2_cond_init (gthread_cond_t ); +extern int __gthread_os2_cond_destroy (__gthread_cond_t ); +extern int gthread_os2_cond_broadcast (gthread_cond_t *); +extern int gthread_os2_cond_wait (gthread_cond_t , __gthread_mutex_t ); +extern int gthread_os2_cond_wait_recursive (gthread_cond_t , + __gthread_recursive_mutex_t ); + +static inline void +gthread_cond_init_function (gthread_cond_t *cond) +{ + gthread_os2_cond_init (cond); +} + +static inline int +gthread_cond_destroy (gthread_cond_t *cond) +{ + return gthread_os2_cond_destroy (cond); +} + +static inline int +gthread_cond_broadcast (gthread_cond_t cond) +{ + return __gthread_os2_cond_broadcast (cond); +} + +static inline int +gthread_cond_wait (gthread_cond_t cond, gthread_mutex_t *mutex) +{ + return gthread_os2_cond_wait (cond, mutex); +} + +static inline int +gthread_cond_wait_recursive (gthread_cond_t *cond, + gthread_recursive_mutex_t *mutex) +{ + return gthread_os2_cond_wait_recursive (cond, mutex); +} + +#define GTHREADS_CXX0X 1 + +#include + +typedef int __gthread_t; + +typedef struct timespec gthread_time_t; + +extern int gthread_os2_create (gthreadt , void () (void_), void ); +extern int gthread_os2_join (gthread_t, void _); +extern int gthread_os2_detach (gthread_t); +extern int gthread_os2_equal (gthread_t, gthread_t); +extern int gthread_os2_self (void); +extern int gthread_os2_yield (void); +extern int __gthread_os2_mutex_timedlock (gthread_mutex_t , + const __gthread_time_t ); +extern int + gthread_os2_recursive_mutex_timedlock (gthread_recursive_mutex_t *,
  • const gthread_time_t *); +extern int gthread_os2_cond_signal (gthread_cond_t *); +extern int gthread_os2_cond_timedwait (gthread_cond_t *, + gthread_mutex_t , + const __gthread_time_t );
  • +static inline int +gthread_create (gthread_t _thread, void (func) (void), void args) +{ + return gthread_os2_create (thread, func, args); +} + +static inline int +__gthread_join (gthread_t thread, void _value_ptr) +{ + return gthread_os2_join (thread, value_ptr); +} + +static inline int +__gthread_detach (gthread_t thread) +{ + return gthread_os2detach (thread); +} + +/* Compare threads. Return non-zero if equal, otherwise 0. / +static inline int +__gthread_equal (gthread_t t1, gthread_t t2) +{ + return gthread_os2_equal (t1, t2); +} + +static inline gthread_t +gthread_self (void) +{ + return gthread_os2_self (); +} + +static inline int +gthread_yield (void) +{ + return gthread_os2_yield (); +} + +static inline int +gthread_mutex_timedlock (__gthread_mutex_t mutex, + const gthread_time_t *abs_timeout) +{ + return gthread_os2_mutex_timedlock (mutex, abs_timeout); +} + +static inline int +gthread_recursive_mutex_timedlock (gthread_recursive_mutex_t mutex, + const __gthread_time_t abs_timeout) +{ + return gthread_os2_recursive_mutex_timedlock (mutex, abs_timeout); +} + +static inline int +gthread_cond_signal (gthread_cond_t *cond) +{ + return __gthread_os2_cond_signal (cond); +} + +static inline int +gthread_cond_timedwait (gthread_cond_t *cond, gthread_mutex_t mutex, + const __gthread_time_t abs_timeout) +{ + return gthread_os2_cond_timedwait (cond, mutex, abs_timeout); +} + +#ifdef cplusplus +} +#endif + #endif /_ not __gthr_os2_h */ -- 2.7.0 |

— Reply to this email directly or view it on GitHub https://github.com/psmedley/gcc/issues/21#issuecomment-183655501.

komh commented 8 years ago

4.9.x. I have no 5.3.x sources.

komh commented 8 years ago

Hmm... I'm considering to update this patch , again.

psmedley commented 8 years ago

Ok, I will hold off. I'm extremely busy at work right now, so my available time is very small.

Cheers,

Paul On 15 Feb 2016 12:35, "KO Myung-Hun" notifications@github.com wrote:

Hmm... I'm considering to update this patch , again.

— Reply to this email directly or view it on GitHub https://github.com/psmedley/gcc/issues/21#issuecomment-184025165.

komh commented 8 years ago

Updated.

  1. Removed DCE_POSTONE dependency.
  2. ACK-based condition variable.

Here is the patch.

From a9bc46b64c2a2bd217c89ee07e334942937be76c Mon Sep 17 00:00:00 2001
From: KO Myung-Hun <komh@chollian.net>
Date: Sun, 31 Jan 2016 21:31:33 +0900
Subject: [PATCH] OS/2: add C++11 thread support

    modified:   libgcc/config.host
    modified:   libgcc/config/i386/libgcc-emx.ver
    new file:   libgcc/config/i386/t-gthr-os2
    new file:   libgcc/gthr-os2.c
    modified:   libgcc/gthr-os2.h
---
 libgcc/config.host                |   5 +
 libgcc/config/i386/libgcc-emx.ver |  26 +++
 libgcc/config/i386/t-gthr-os2     |   2 +
 libgcc/gthr-os2.c                 | 455 ++++++++++++++++++++++++++++++++++++++
 libgcc/gthr-os2.h                 | 236 +++++++++++++++-----
 5 files changed, 667 insertions(+), 57 deletions(-)
 create mode 100644 libgcc/config/i386/t-gthr-os2
 create mode 100644 libgcc/gthr-os2.c

diff --git a/libgcc/config.host b/libgcc/config.host
index 9f021a1..c92fdb9 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -686,6 +686,11 @@ i[34567]86-*-interix[3-9]*)
    ;;
 i*86-pc-*emx)      # i?86 running OS/2
    tmake_file="$tmake_file i386/t-emx"
+   case ${target_thread_file} in
+     os2)
+       tmake_file="$tmake_file i386/t-gthr-os2"
+       ;;
+   esac
    extra_parts="$extra_parts emx-ctordtor.o"
    host_exeext=.exe
    ;;
diff --git a/libgcc/config/i386/libgcc-emx.ver b/libgcc/config/i386/libgcc-emx.ver
index 03ba5ec..b8fecac 100644
--- a/libgcc/config/i386/libgcc-emx.ver
+++ b/libgcc/config/i386/libgcc-emx.ver
@@ -19,3 +19,29 @@
 # Export custom EMX/KLIBC build symbols

 __chkstk_ms
+
+# __GTHREADS
+__gthread_os2_mutex_init
+__gthread_os2_mutex_destroy
+__gthread_os2_mutex_lock
+__gthread_os2_mutex_trylock
+__gthread_os2_mutex_unlock
+
+# __GTHREAD_HAS_COND
+__gthread_os2_cond_init
+__gthread_os2_cond_destroy
+__gthread_os2_cond_broadcast
+__gthread_os2_cond_wait
+__gthread_os2_cond_wait_recursive
+
+# __GTHREADS_CXX0X
+__gthread_os2_create
+__gthread_os2_join
+__gthread_os2_detach
+__gthread_os2_equal
+__gthread_os2_self
+__gthread_os2_yield
+__gthread_os2_mutex_timedlock
+__gthread_os2_recursive_mutex_timedlock
+__gthread_os2_cond_signal
+__gthread_os2_cond_timedwait
diff --git a/libgcc/config/i386/t-gthr-os2 b/libgcc/config/i386/t-gthr-os2
new file mode 100644
index 0000000..4cf4e55
--- /dev/null
+++ b/libgcc/config/i386/t-gthr-os2
@@ -0,0 +1,2 @@
+# We hide calls to OS/2 APIs needed for OS/2 thread support here:
+LIB2ADD = $(srcdir)/gthr-os2.c
diff --git a/libgcc/gthr-os2.c b/libgcc/gthr-os2.c
new file mode 100644
index 0000000..40329d1
--- /dev/null
+++ b/libgcc/gthr-os2.c
@@ -0,0 +1,455 @@
+/* Threads compatibily routines for libgcc2.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+   Contributed by KO Myung-Hun <komh@chollian.net>.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+#define INCL_DOS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/builtin.h>
+#include <sys/fmutex.h>
+#include <sys/time.h>
+
+#include "gthr-os2.h"
+
+void
+__gthread_os2_mutex_init (__gthread_mutex_t *mutex, int recursive)
+{
+  mutex->recursive = recursive;
+  DosCreateMutexSem (NULL, (PHMTX) &mutex->mtx, 0, FALSE);
+}
+
+int
+__gthread_os2_mutex_destroy (__gthread_mutex_t *mutex, int recursive)
+{
+  if (mutex->recursive != recursive)
+    return 1;
+
+  return DosCloseMutexSem ((HMTX) mutex->mtx);
+}
+
+static int
+__gthread_os2_mutex_lock_common (__gthread_mutex_t *mutex, int recursive,
+                                 ULONG ulTimeout)
+{
+  PID pid;
+  TID tid;
+  ULONG ulCount;
+
+  if (mutex->recursive != recursive)
+    return 1;
+
+  /* Initialize static mutex.  */
+  if ((HMTX) mutex->mtx == NULLHANDLE)
+    {
+      /* FIXME: resource leaks.  */
+      _fmutex_request (&mutex->static_lock, _FMR_IGNINT);
+      if ((HMTX) mutex->mtx == NULLHANDLE)
+        __gthread_os2_mutex_init (mutex, recursive);
+      _fmutex_release (&mutex->static_lock);
+    }
+
+  if (DosRequestMutexSem ((HMTX) mutex->mtx, ulTimeout))
+    return 1;
+
+  DosQueryMutexSem ((HMTX) mutex->mtx, &pid, &tid, &ulCount);
+
+  /* non-recursive trylock ? */
+  if (!mutex->recursive && ulTimeout == SEM_IMMEDIATE_RETURN && ulCount > 1)
+    {
+      DosReleaseMutexSem ((HMTX) mutex->mtx);
+
+      return 1;
+    }
+
+  assert (!"Dead lock" || mutex->recursive || ulCount == 1);
+
+  return 0;
+}
+
+int
+__gthread_os2_mutex_lock (__gthread_mutex_t *mutex, int recursive)
+{
+  return __gthread_os2_mutex_lock_common (mutex, recursive,
+                                          SEM_INDEFINITE_WAIT);
+}
+
+int
+__gthread_os2_mutex_trylock (__gthread_mutex_t *mutex, int recursive)
+{
+  return __gthread_os2_mutex_lock_common (mutex, recursive,
+                                          SEM_IMMEDIATE_RETURN);
+}
+
+int
+__gthread_os2_mutex_unlock (__gthread_mutex_t *mutex, int recursive)
+{
+  if (mutex->recursive != recursive)
+    return 1;
+
+  return DosReleaseMutexSem ((HMTX) mutex->mtx);
+}
+
+void
+__gthread_os2_cond_init (__gthread_cond_t *cond)
+{
+  DosCreateEventSem (NULL, (PHEV) &cond->ev, 0, FALSE);
+  DosCreateEventSem (NULL, (PHEV) &cond->ack, 0, FALSE);
+  cond->signaled = 0;
+  cond->waiters = 0;
+}
+
+int
+__gthread_os2_cond_destroy (__gthread_cond_t *cond)
+{
+  return DosCloseEventSem ((HEV) cond->ev) ||
+         DosCloseEventSem ((HEV) cond->ack);
+}
+
+static void
+__gthread_os2_static_cond_init (__gthread_cond_t *cond)
+{
+  /* FIXME: resource leaks */
+  _fmutex_request (&cond->static_lock, _FMR_IGNINT);
+  if ((HEV) cond->ev == NULLHANDLE)
+     __gthread_os2_cond_init (cond);
+  _fmutex_release (&cond->static_lock);
+}
+
+int
+__gthread_os2_cond_broadcast (__gthread_cond_t *cond)
+{
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  while (!__atomic_cmpxchg32 (&cond->waiters, 0, 0))
+    __gthread_os2_cond_signal (cond);
+
+  return 0;
+}
+
+static int
+__gthread_os2_cond_wait_common (__gthread_cond_t *cond,
+                                __gthread_mutex_t *mutex,
+                                int recursive, ULONG ulTimeout)
+{
+  ULONG ulPost;
+  APIRET rc;
+
+  if (mutex->recursive != recursive)
+    return 1;
+
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  __atomic_increment (&cond->waiters);
+
+  __gthread_os2_mutex_unlock (mutex, recursive);
+
+  do
+    {
+      rc = DosWaitEventSem ((HEV) cond->ev, ulTimeout);
+      if (rc == NO_ERROR)
+        DosResetEventSem ((HEV) cond->ev, &ulPost);
+    } while (rc == NO_ERROR && !__atomic_cmpxchg32 (&cond->signaled, 0, 1));
+
+  __atomic_decrement (&cond->waiters);
+
+  DosPostEventSem ((HEV) cond->ack);
+
+  __gthread_os2_mutex_lock (mutex, recursive);
+
+  return rc;
+}
+
+int
+__gthread_os2_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 0, SEM_INDEFINITE_WAIT);
+}
+
+int
+__gthread_os2_cond_wait_recursive (__gthread_cond_t *cond,
+                                   __gthread_recursive_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 1, SEM_INDEFINITE_WAIT);
+}
+
+typedef struct __gthread_os2_s __gthread_os2_t;
+
+struct __gthread_os2_s {
+  __gthread_t tid;
+  void *(*func) (void*);
+  void *args;
+  void *result;
+  HEV hevQuit;
+  HEV hevDone;
+  int detached;
+  __gthread_os2_t *next;
+};
+
+static __gthread_os2_t main_thread =
+  { 1, NULL, NULL, NULL, NULLHANDLE, NULLHANDLE, 0, NULL };
+
+static __gthread_os2_t *__gthread_os2_thread_start = &main_thread;
+
+static __gthread_os2_t *
+__gthread_os2_thread_new (void *(*func) (void*), void *args)
+{
+  __gthread_os2_t *new_thread;
+
+  new_thread = calloc (1, sizeof (*new_thread));
+  if (new_thread)
+    {
+      new_thread->func = func;
+      new_thread->args = args;
+      DosCreateEventSem (NULL, &new_thread->hevQuit, 0, FALSE);
+      DosCreateEventSem (NULL, &new_thread->hevDone, 0, FALSE);
+    }
+
+  return new_thread;
+}
+
+static void
+__gthread_os2_thread_free (__gthread_os2_t *thread)
+{
+  if (thread == &main_thread)
+    return;
+
+  DosCloseEventSem (thread->hevQuit);
+  DosCloseEventSem (thread->hevDone);
+
+  free (thread);
+}
+
+static __gthread_os2_t *
+__gthread_os2_thread_find (__gthread_t tid)
+{
+  __gthread_os2_t *thread = __gthread_os2_thread_start;
+
+  while (thread && thread->tid != tid)
+    thread = thread->next;
+
+  return thread;
+}
+
+static void
+__gthread_os2_thread_add (__gthread_os2_t *thread, __gthread_t tid)
+{
+  thread->tid = tid;
+  thread->next = __gthread_os2_thread_start;
+
+  __gthread_os2_thread_start = thread;
+}
+
+static void
+__gthread_os2_thread_del (__gthread_os2_t *thread)
+{
+  if (thread == &main_thread)
+    return;
+
+  if (thread == __gthread_os2_thread_start)
+    __gthread_os2_thread_start = thread->next;
+  else
+    {
+      __gthread_os2_t *prev;
+
+      for (prev = __gthread_os2_thread_start; prev->next != thread;
+           prev = prev->next)
+        /* nothing */;
+
+      prev->next = thread->next;
+    }
+
+  __gthread_os2_thread_free (thread);
+}
+
+static void thread_entry (void *args)
+{
+  __gthread_os2_t *th = (__gthread_os2_t *)args;
+  int detached;
+
+  th->result = th->func(th->args);
+  DosWaitEventSem (th->hevQuit, SEM_INDEFINITE_WAIT);
+
+  detached = th->detached;
+
+  DosPostEventSem (th->hevDone);
+
+  if (detached)
+    __gthread_os2_thread_del (th);
+}
+
+int
+__gthread_os2_create (__gthread_t *thread, void *(*func) (void*), void *args)
+{
+  __gthread_os2_t *th;
+  int tid;
+
+  th = __gthread_os2_thread_new (func, args);
+  if (!th)
+    return ENOMEM;
+
+  tid = _beginthread (thread_entry, NULL, 1024 * 1024, th);
+  if (tid == -1)
+    {
+      __gthread_os2_thread_free (th);
+
+      return 1;
+    }
+
+  __gthread_os2_thread_add (th, tid);
+
+  *thread = tid;
+
+  return 0;
+}
+
+int
+__gthread_os2_join (__gthread_t thread, void **value_ptr)
+{
+  __gthread_os2_t *th;
+
+  th = __gthread_os2_thread_find (thread);
+
+  if (!th || th->detached)
+    return 1;
+
+  DosPostEventSem (th->hevQuit);
+
+  if (DosWaitEventSem (th->hevDone, SEM_INDEFINITE_WAIT))
+    return 1;
+
+  if (value_ptr)
+    *value_ptr = th->result;
+
+  __gthread_os2_thread_del (th);
+
+  return 0;
+}
+
+int
+__gthread_os2_detach (__gthread_t thread)
+{
+  __gthread_os2_t *th;
+
+  th = __gthread_os2_thread_find (thread);
+  if (!th)
+    return 1;
+
+  th->detached = 1;
+
+  DosPostEventSem (th->hevQuit);
+
+  return 0;
+}
+
+/* Compare threads. Return non-zero if same, otherwise 0.  */
+int
+__gthread_os2_equal (__gthread_t t1, __gthread_t t2)
+{
+  return t1 == t2;
+}
+
+__gthread_t
+__gthread_os2_self (void)
+{
+  return _gettid();
+}
+
+int
+__gthread_os2_yield (void)
+{
+  DosSleep (0);
+
+  return 0;
+}
+
+static ULONG
+__gthread_os2_abs2rem (const __gthread_time_t *abs_timeout)
+{
+  struct timeval tv;
+  ULONG ulNow;
+  ULONG ulDeadline;
+  ULONG ulRemain;
+
+  gettimeofday (&tv, NULL);
+  ulNow = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+  ulDeadline = abs_timeout->tv_sec * 1000 + abs_timeout->tv_nsec / 1000000UL;
+  ulRemain = (ulDeadline > ulNow) ? (ulDeadline - ulNow) : 0;
+
+  return ulRemain;
+}
+
+int
+__gthread_os2_mutex_timedlock (__gthread_mutex_t *mutex,
+                               const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_lock_common (mutex, 0,
+                                          __gthread_os2_abs2rem (abs_timeout));
+}
+
+int
+__gthread_os2_recursive_mutex_timedlock (__gthread_recursive_mutex_t *mutex,
+                                         const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_lock_common (mutex, 1,
+                                          __gthread_os2_abs2rem (abs_timeout));
+}
+
+int
+__gthread_os2_cond_signal (__gthread_cond_t *cond)
+{
+  ULONG ulPost;
+
+  if ((HEV) cond->ev == NULLHANDLE)
+    __gthread_os2_static_cond_init (cond);
+
+  DosResetEventSem ((HEV) cond->ack, &ulPost);
+
+  if (!__atomic_cmpxchg32 (&cond->waiters, 0, 0))
+    {
+      __atomic_xchg (&cond->signaled, 1);
+      DosPostEventSem ((HEV) cond->ev);
+
+      DosWaitEventSem ((HEV) cond->ack, SEM_INDEFINITE_WAIT);
+    }
+
+  return 0;
+}
+
+int
+__gthread_os2_cond_timedwait (__gthread_cond_t *cond, __gthread_mutex_t *mutex,
+                              const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_cond_wait_common (cond, mutex, 0,
+                                         __gthread_os2_abs2rem (abs_timeout));
+}
diff --git a/libgcc/gthr-os2.h b/libgcc/gthr-os2.h
index ac4f709..ac36f5b 100644
--- a/libgcc/gthr-os2.h
+++ b/libgcc/gthr-os2.h
@@ -1,6 +1,7 @@
 /* Threads compatibily routines for libgcc2.  */
 /* Compile this one with gcc.  */
-/* Copyright (C) 1997 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2016 Free Software Foundation, Inc.
+   Contributed by KO Myung-Hun <komh@chollian.net>.

 This file is part of GNU CC.

@@ -33,6 +34,10 @@ Boston, MA 02111-1307, USA.  */
 #error "gthr-os2.h doesn't implement the _LIBOBJC mode!"
 #endif 

+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define __GTHREADS 1

 /* OS/2 threads specific definitions */
@@ -46,21 +51,24 @@ Boston, MA 02111-1307, USA.  */
 #include <InnoTekLIBC/backend.h>

 typedef int __gthread_key_t;
+
 typedef struct 
 {
   signed char volatile done;
   signed char volatile started;
 } __gthread_once_t;
-typedef _fmutex __gthread_mutex_t;
+
 typedef struct {
-  long depth;
-  uint32_t owner;
-  _fmutex actual;
-} __gthread_recursive_mutex_t;
+  int recursive;
+  unsigned long mtx;
+  _fmutex static_lock;
+} __gthread_mutex_t, __gthread_recursive_mutex_t;

 #define __GTHREAD_ONCE_INIT        { 0, 0 }
-#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
+#define __GTHREAD_MUTEX_INIT    { 0, 0, _FMUTEX_INITIALIZER }
 #define __GTHREAD_MUTEX_INIT_FUNCTION  __gthread_mutex_init_function
+#define __GTHREAD_RECURSIVE_MUTEX_INIT { 1, 0, _FMUTEX_INITIALIZER }
+#define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function

 static inline int
 __gthread_active_p (void)
@@ -95,99 +103,70 @@ __gthread_once (__gthread_once_t *once, void (*func) (void))
   return 0;
 }

+extern void __gthread_os2_mutex_init (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_destroy (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_lock (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_trylock (__gthread_mutex_t *, int);
+extern int __gthread_os2_mutex_unlock (__gthread_mutex_t *, int);
+
 static inline void
 __gthread_mutex_init_function (__gthread_mutex_t *mutex)
 {
-  _fmutex_create (mutex, 0);
+  __gthread_os2_mutex_init (mutex, 0);
 }

 static inline int
 __gthread_mutex_destroy (__gthread_mutex_t *mutex )
 {
-  return 0;
+  return __gthread_os2_mutex_destroy (mutex, 0);
 }

 static inline int
 __gthread_mutex_lock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_request (mutex, _FMR_IGNINT);
+  return __gthread_os2_mutex_lock (mutex, 0);
 }

 static inline int
 __gthread_mutex_trylock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_request (mutex, _FMR_IGNINT | _FMR_NOWAIT);
+  return __gthread_os2_mutex_trylock (mutex, 0);
 }

 static inline int
 __gthread_mutex_unlock (__gthread_mutex_t *mutex)
 {
-  return _fmutex_release (mutex);
+  return __gthread_os2_mutex_unlock (mutex, 0);
 }

-static inline int
+static inline void
 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
 {
-  mutex->depth = 0;
-  mutex->owner = fibGetTidPid();
-  return _fmutex_create (&mutex->actual, 0);
+  __gthread_os2_mutex_init (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      uint32_t me = fibGetTidPid();
-
-      if (mutex->owner != me)
-   {
-     __gthread_mutex_lock(&mutex->actual);
-     mutex->owner = me;
-   }
-
-      mutex->depth++;
-    }
-  return 0;
+  return __gthread_os2_mutex_destroy (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      uint32_t me = fibGetTidPid();
-
-      if (mutex->owner != me)
-   {
-     if (__gthread_mutex_trylock(&mutex->actual))
-       return 1;
-     mutex->owner = me;
-   }
-
-      mutex->depth++;
-    }
-  return 0;
+  return __gthread_os2_mutex_lock (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
+__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
 {
-  if (__gthread_active_p ())
-    {
-      if (--mutex->depth == 0)
-   {
-      mutex->owner = fibGetTidPid();
-      __gthread_mutex_unlock(&mutex->actual);
-   }
-    }
-  return 0;
+  return __gthread_os2_mutex_trylock (mutex, 1);
 }

 static inline int
-__gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
+__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
 {
-  return 0;
+  return __gthread_os2_mutex_unlock (mutex, 1);
 }

 static inline int
@@ -231,4 +210,147 @@ __gthread_setspecific (__gthread_key_t key, const void *ptr)
   return 0;
 }

+#define __GTHREAD_HAS_COND 1
+
+typedef struct {
+  unsigned long ev;
+  unsigned long ack;
+  unsigned volatile signaled;
+  unsigned volatile waiters;
+  _fmutex static_lock;
+} __gthread_cond_t;
+
+#define __GTHREAD_COND_INIT { 0, 0, 0, 0, _FMUTEX_INITIALIZER }
+#define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init_function
+
+extern void __gthread_os2_cond_init (__gthread_cond_t *);
+extern int __gthread_os2_cond_destroy (__gthread_cond_t *);
+extern int __gthread_os2_cond_broadcast (__gthread_cond_t *);
+extern int __gthread_os2_cond_wait (__gthread_cond_t *, __gthread_mutex_t *);
+extern int __gthread_os2_cond_wait_recursive (__gthread_cond_t *,
+                                              __gthread_recursive_mutex_t *);
+
+static inline void
+__gthread_cond_init_function (__gthread_cond_t *cond)
+{
+  __gthread_os2_cond_init (cond);
+}
+
+static inline int
+__gthread_cond_destroy (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_destroy (cond);
+}
+
+static inline int
+__gthread_cond_broadcast (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_broadcast (cond);
+}
+
+static inline int
+__gthread_cond_wait (__gthread_cond_t *cond, __gthread_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait (cond, mutex);
+}
+
+static inline int
+__gthread_cond_wait_recursive (__gthread_cond_t *cond,
+                               __gthread_recursive_mutex_t *mutex)
+{
+  return __gthread_os2_cond_wait_recursive (cond, mutex);
+}
+
+#define __GTHREADS_CXX0X 1
+
+#include <time.h>
+
+typedef int __gthread_t;
+
+typedef struct timespec __gthread_time_t;
+
+extern int __gthread_os2_create (__gthread_t *, void *(*) (void*), void *);
+extern int __gthread_os2_join (__gthread_t, void **);
+extern int __gthread_os2_detach (__gthread_t);
+extern int __gthread_os2_equal (__gthread_t, __gthread_t);
+extern int __gthread_os2_self (void);
+extern int __gthread_os2_yield (void);
+extern int __gthread_os2_mutex_timedlock (__gthread_mutex_t *,
+                                          const __gthread_time_t *);
+extern int
+  __gthread_os2_recursive_mutex_timedlock (__gthread_recursive_mutex_t *,
+                                           const __gthread_time_t *);
+extern int __gthread_os2_cond_signal (__gthread_cond_t *);
+extern int __gthread_os2_cond_timedwait (__gthread_cond_t *,
+                                         __gthread_mutex_t *,
+                                         const __gthread_time_t *);
+
+static inline int
+__gthread_create (__gthread_t *thread, void *(*func) (void*), void *args)
+{
+  return __gthread_os2_create (thread, func, args);
+}
+
+static inline int
+__gthread_join (__gthread_t thread, void **value_ptr)
+{
+  return __gthread_os2_join (thread, value_ptr);
+}
+
+static inline int
+__gthread_detach (__gthread_t thread)
+{
+  return __gthread_os2_detach (thread);
+}
+
+/* Compare threads. Return non-zero if equal, otherwise 0.  */
+static inline int
+__gthread_equal (__gthread_t t1, __gthread_t t2)
+{
+  return __gthread_os2_equal (t1, t2);
+}
+
+static inline __gthread_t
+__gthread_self (void)
+{
+  return __gthread_os2_self ();
+}
+
+static inline int
+__gthread_yield (void)
+{
+  return __gthread_os2_yield ();
+}
+
+static inline int
+__gthread_mutex_timedlock (__gthread_mutex_t *mutex,
+                           const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_mutex_timedlock (mutex, abs_timeout);
+}
+
+static inline int
+__gthread_recursive_mutex_timedlock (__gthread_recursive_mutex_t *mutex,
+                                     const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_recursive_mutex_timedlock (mutex, abs_timeout);
+}
+
+static inline int
+__gthread_cond_signal (__gthread_cond_t *cond)
+{
+  return __gthread_os2_cond_signal (cond);
+}
+
+static inline int
+__gthread_cond_timedwait (__gthread_cond_t *cond, __gthread_mutex_t *mutex,
+                          const __gthread_time_t *abs_timeout)
+{
+  return __gthread_os2_cond_timedwait (cond, mutex, abs_timeout);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* not __gthr_os2_h */
-- 
2.7.0
komh commented 8 years ago

Pushed as commit e012188309ff098911c960c2b44472aa99239cb1.

dmik commented 8 years ago

@komh Thank you! Could you please explain why in particular you decided to replace gthread fmutex-based mutex implementatns to native OS/2?

komh commented 8 years ago

Due to timed-mutex.

komh commented 8 years ago

Any problem ?

dmik commented 8 years ago

It's not a problem. The thing is gcc is a very important piece of software with virtually everything else depending on it so its important to understand why your implementation should be preferred over the existing one. My concern is that kLIBC fmutex is faster than the OS/2 kernel mutex...

So, you mean that the existing fmutex-based impl doesn't provide timed mutexes?

komh commented 8 years ago

Is kLIBC fmutex really faster tha OS/2 mutex ? I know, fmutex is based on an OS/2 event semaphore. And I don't think, event semaphore is faster than mutex. But fmutex can hides OS/2 APIs.

I don't know that fmutex support timed-mutex. Are there fmutex stuffs for timed mutex ?

dmik commented 8 years ago

IIRC fmutex stands for "fast mutex" and was done by Knut to reduce overhead costs in most frequent code paths (and it involves atomic operations for that a lot). The kernel event semaphore is only involved when it's absolutely necessary to wait. In all other cases no expensive kernel calls are made.

Regarding extending fmutex to implement timed mutex, I will try to consult Knut (I don't have time to look closer into this at the moment).

komh commented 8 years ago

fmutex may stand for "fast mutex". But I don't know that Knut implemented it. But copyright header says Eberhard Mattes, the developer of EMX, and fmutex is there in EMX, too.

Anyway, fmutex implementation are based on event semaphore(HEV) as I said above. It uses atomic operations for owner check primarily and for assinging an evernt semaphore. See http://trac.netlabs.org/libc/browser/branches/libc-0.6/src/emx/src/lib/process/fmutex.c.

I don't feel to stick to fmutex. However, if fmutex support timed-mutex, then it would be good. Because there is no need to include os2.h to use mutex. In addition, fmutex supports a static initializer.

dmik commented 8 years ago

You may be right that the original author is Eberhard but as I see in the revision history, Knut did a bunch of enhancements over the years. So I asked him to comment on this, let's check his opinion.