Am 01.10.2017 um 10:59 schrieb Bernd Edlinger:
maybe there is a way how you could explicitly join
all running threads?

Yes, that seems to do the trick. Thanks!

Here is a patch which appears to work. It does hit a snag with static
linking, though, because it calls __gthread_self (), and that causes
a segfault with -static :-(.

The test case in question is static_linking_1.f.

This appears to be a general problem, and has  been discussed
before, for example in
https://gcc.gnu.org/ml/gcc-help/2010-05/msg00029.html .

What would be the best way to proceed? Modify the behavior of -static
with gfortran?

Regards

        Thomas

2017-10-01 Thomas Koenig <tkoe...@gcc.gnu.org>


PR fortran/66756 PR fortran/82378 * io/io.h: Add field th to gfc_unit. Add prototypes for lock_unit and trylock_unit. * io/unit.c (insert_unit): Do not create lock and lock, move to (gfc_get_unit): here; lock after insert_unit has succeded. Use lock_unit and trylock_unit instead of __gthread_mutex_lock and __gthread_mutex_trylock. (init_units): Do not unlock unit locks for stdin, stdout and stderr. (lock_unit): New function. (trylock_unit): New function. (close_units): If a unit still has a lock, wait for the completion of the corresponding thread. * io/unix.c (find_file): Use lock_unit and trylock_unit instead of __gthread_mutex_lock and __gthread_mutex_trylock. (flush_all_units): Likewise.

2017-10-01  Thomas Koenig  <tkoe...@gcc.gnu.org>

        PR fortran/66756
        PR fortran/82378
        * gfortran.dg/openmp-close.f90: New test.
Index: io/io.h
===================================================================
--- io/io.h	(Revision 253162)
+++ io/io.h	(Arbeitskopie)
@@ -661,6 +661,8 @@ typedef struct gfc_unit
   int continued;
 
   __gthread_mutex_t lock;
+  /* ID of the thread currently holding the lock.  */
+  __gthread_t th;
   /* Number of threads waiting to acquire this unit's lock.
      When non-zero, close_unit doesn't only removes the unit
      from the UNIT_ROOT tree, but doesn't free it and the
@@ -764,6 +766,12 @@ internal_proto(get_unit);
 extern void unlock_unit (gfc_unit *);
 internal_proto(unlock_unit);
 
+extern void lock_unit (gfc_unit *);
+internal_proto(lock_unit);
+
+extern int trylock_unit (gfc_unit *);
+internal_proto (trylock_unit);
+
 extern void finish_last_advance_record (gfc_unit *u);
 internal_proto (finish_last_advance_record);
 
Index: io/unit.c
===================================================================
--- io/unit.c	(Revision 253162)
+++ io/unit.c	(Arbeitskopie)
@@ -221,9 +221,9 @@ insert (gfc_unit *new, gfc_unit *t)
   return t;
 }
 
+/* insert_unit()-- Create a new node, insert it into the treap.  It is assumed
+   that the caller holds unit_lock.  */
 
-/* insert_unit()-- Create a new node, insert it into the treap.  */
-
 static gfc_unit *
 insert_unit (int n)
 {
@@ -237,7 +237,6 @@ insert_unit (int n)
 #else
   __GTHREAD_MUTEX_INIT_FUNCTION (&u->lock);
 #endif
-  __gthread_mutex_lock (&u->lock);
   u->priority = pseudo_random ();
   unit_root = insert (u, unit_root);
   return u;
@@ -361,9 +360,12 @@ retry:
 
   if (created)
     {
-      /* Newly created units have their lock held already
-	 from insert_unit.  Just unlock UNIT_LOCK and return.  */
       __gthread_mutex_unlock (&unit_lock);
+
+      /* Nobody outside this address has seen this unit yet.  We could safely
+	 keep it unlocked until now.  */
+      
+      lock_unit (p);
       return p;
     }
 
@@ -371,7 +373,7 @@ found:
   if (p != NULL && (p->child_dtio == 0))
     {
       /* Fast path.  */
-      if (! __gthread_mutex_trylock (&p->lock))
+      if (! trylock_unit (p))
 	{
 	  /* assert (p->closed == 0); */
 	  __gthread_mutex_unlock (&unit_lock);
@@ -386,7 +388,7 @@ found:
 
   if (p != NULL && (p->child_dtio == 0))
     {
-      __gthread_mutex_lock (&p->lock);
+      lock_unit (p);
       if (p->closed)
 	{
 	  __gthread_mutex_lock (&unit_lock);
@@ -616,10 +618,9 @@ init_units (void)
       u->endfile = NO_ENDFILE;
 
       u->filename = strdup (stdin_name);
+      u->th = __gthread_self ();
 
       fbuf_init (u, 0);
-
-      __gthread_mutex_unlock (&u->lock);
     }
 
   if (options.stdout_unit >= 0)
@@ -647,10 +648,9 @@ init_units (void)
       u->endfile = AT_ENDFILE;
 
       u->filename = strdup (stdout_name);
+      u->th = __gthread_self ();
 
       fbuf_init (u, 0);
-
-      __gthread_mutex_unlock (&u->lock);
     }
 
   if (options.stderr_unit >= 0)
@@ -677,11 +677,10 @@ init_units (void)
       u->endfile = AT_ENDFILE;
 
       u->filename = strdup (stderr_name);
+      u->th = __gthread_self ();
 
       fbuf_init (u, 256);  /* 256 bytes should be enough, probably not doing
                               any kind of exotic formatting to stderr.  */
-
-      __gthread_mutex_unlock (&u->lock);
     }
 
   /* Calculate the maximum file offset in a portable manner.
@@ -745,6 +744,28 @@ unlock_unit (gfc_unit *u)
   __gthread_mutex_unlock (&u->lock);
 }
 
+
+/* Lock a unit and record the thread id.  */
+
+void
+lock_unit (gfc_unit *u)
+{
+  __gthread_mutex_lock (&u->lock);
+  u->th = __gthread_self ();
+}
+
+/* Try to lock a unit lock and record the thread id on success.  */
+
+int
+trylock_unit (gfc_unit *u)
+{
+  int ret = __gthread_mutex_trylock (&u->lock);
+  if (ret)
+    u->th = __gthread_self();
+  
+  return ret;  
+}
+
 /* close_unit()-- Close a unit.  The stream is closed, and any memory
    associated with the stream is freed.  Returns nonzero on I/O error.
    Should be called with the u->lock locked. */
@@ -756,12 +777,9 @@ close_unit (gfc_unit *u)
 }
 
 
-/* close_units()-- Delete units on completion.  We just keep deleting
-   the root of the treap until there is nothing left.
-   Not sure what to do with locking here.  Some other thread might be
-   holding some unit's lock and perhaps hold it indefinitely
-   (e.g. waiting for input from some pipe) and close_units shouldn't
-   delay the program too much.  */
+/* close_units()-- Delete units on completion.  We just keep deleting the root
+   of the treap until there is nothing left.  If a thread is still locked, we
+   wait for its completion and unlock, then call close_unit_1.  */
 
 void
 close_units (void)
@@ -768,7 +786,14 @@ close_units (void)
 {
   __gthread_mutex_lock (&unit_lock);
   while (unit_root != NULL)
-    close_unit_1 (unit_root, 1);
+    {
+      if (!trylock_unit (unit_root) &&
+	  !__gthread_equal (unit_root->th, __gthread_self ()))
+	__gthread_join (unit_root->th, NULL);
+
+      unlock_unit (unit_root);
+      close_unit_1 (unit_root, 1);
+    }
   __gthread_mutex_unlock (&unit_lock);
 
   free (newunits);
Index: io/unix.c
===================================================================
--- io/unix.c	(Revision 253162)
+++ io/unix.c	(Arbeitskopie)
@@ -1714,7 +1714,7 @@ retry:
   if (u != NULL)
     {
       /* Fast path.  */
-      if (! __gthread_mutex_trylock (&u->lock))
+      if (! trylock_unit (u))
 	{
 	  /* assert (u->closed == 0); */
 	  __gthread_mutex_unlock (&unit_lock);
@@ -1726,7 +1726,7 @@ retry:
   __gthread_mutex_unlock (&unit_lock);
   if (u != NULL)
     {
-      __gthread_mutex_lock (&u->lock);
+      lock_unit (u);
       if (u->closed)
 	{
 	  __gthread_mutex_lock (&unit_lock);
@@ -1756,7 +1756,7 @@ flush_all_units_1 (gfc_unit *u, int min_unit)
 	}
       if (u->unit_number >= min_unit)
 	{
-	  if (__gthread_mutex_trylock (&u->lock))
+	  if (trylock_unit (u))
 	    return u;
 	  if (u->s)
 	    sflush (u->s);
@@ -1783,7 +1783,7 @@ flush_all_units (void)
       if (u == NULL)
 	return;
 
-      __gthread_mutex_lock (&u->lock);
+      lock_unit (u);
 
       min_unit = u->unit_number + 1;
 
! { dg-do run }
! { dg-require-effective-target fopenmp }
! { dg-additional-options "-fopenmp" }
program main
  use omp_lib
  !$OMP PARALLEL NUM_THREADS(100)
  write (10,*) 'asdf'
  !$OMP END PARALLEL 
  close(10,status="delete")
end program main

Reply via email to