Home | History | Annotate | Line # | Download | only in posix
      1  1.12  mrg /* Copyright (C) 2005-2022 Free Software Foundation, Inc.
      2   1.1  mrg    Contributed by Richard Henderson <rth (at) redhat.com>.
      3   1.1  mrg 
      4   1.5  mrg    This file is part of the GNU Offloading and Multi Processing Library
      5   1.5  mrg    (libgomp).
      6   1.1  mrg 
      7   1.1  mrg    Libgomp is free software; you can redistribute it and/or modify it
      8   1.1  mrg    under the terms of the GNU General Public License as published by
      9   1.1  mrg    the Free Software Foundation; either version 3, or (at your option)
     10   1.1  mrg    any later version.
     11   1.1  mrg 
     12   1.1  mrg    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
     13   1.1  mrg    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     14   1.1  mrg    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     15   1.1  mrg    more details.
     16   1.1  mrg 
     17   1.1  mrg    Under Section 7 of GPL version 3, you are granted additional
     18   1.1  mrg    permissions described in the GCC Runtime Library Exception, version
     19   1.1  mrg    3.1, as published by the Free Software Foundation.
     20   1.1  mrg 
     21   1.1  mrg    You should have received a copy of the GNU General Public License and
     22   1.1  mrg    a copy of the GCC Runtime Library Exception along with this program;
     23   1.1  mrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24   1.1  mrg    <http://www.gnu.org/licenses/>.  */
     25   1.1  mrg 
     26   1.1  mrg /* This is the default implementation of a barrier synchronization mechanism
     27   1.1  mrg    for libgomp.  This type is private to the library.  Note that we rely on
     28   1.1  mrg    being able to adjust the barrier count while threads are blocked, so the
     29   1.1  mrg    POSIX pthread_barrier_t won't work.  */
     30   1.1  mrg 
     31   1.1  mrg #include "libgomp.h"
     32   1.1  mrg 
     33   1.1  mrg 
     34   1.1  mrg void
     35   1.1  mrg gomp_barrier_init (gomp_barrier_t *bar, unsigned count)
     36   1.1  mrg {
     37   1.1  mrg   gomp_mutex_init (&bar->mutex1);
     38   1.1  mrg #ifndef HAVE_SYNC_BUILTINS
     39   1.1  mrg   gomp_mutex_init (&bar->mutex2);
     40   1.1  mrg #endif
     41   1.1  mrg   gomp_sem_init (&bar->sem1, 0);
     42   1.1  mrg   gomp_sem_init (&bar->sem2, 0);
     43   1.1  mrg   bar->total = count;
     44   1.1  mrg   bar->arrived = 0;
     45   1.1  mrg   bar->generation = 0;
     46   1.5  mrg   bar->cancellable = false;
     47   1.1  mrg }
     48   1.1  mrg 
     49   1.1  mrg void
     50   1.1  mrg gomp_barrier_destroy (gomp_barrier_t *bar)
     51   1.1  mrg {
     52   1.1  mrg   /* Before destroying, make sure all threads have left the barrier.  */
     53   1.1  mrg   gomp_mutex_lock (&bar->mutex1);
     54   1.1  mrg   gomp_mutex_unlock (&bar->mutex1);
     55   1.1  mrg 
     56   1.1  mrg   gomp_mutex_destroy (&bar->mutex1);
     57   1.1  mrg #ifndef HAVE_SYNC_BUILTINS
     58   1.1  mrg   gomp_mutex_destroy (&bar->mutex2);
     59   1.1  mrg #endif
     60   1.1  mrg   gomp_sem_destroy (&bar->sem1);
     61   1.1  mrg   gomp_sem_destroy (&bar->sem2);
     62   1.1  mrg }
     63   1.1  mrg 
     64   1.1  mrg void
     65   1.1  mrg gomp_barrier_reinit (gomp_barrier_t *bar, unsigned count)
     66   1.1  mrg {
     67   1.1  mrg   gomp_mutex_lock (&bar->mutex1);
     68   1.1  mrg   bar->total = count;
     69   1.1  mrg   gomp_mutex_unlock (&bar->mutex1);
     70   1.1  mrg }
     71   1.1  mrg 
     72   1.1  mrg void
     73   1.1  mrg gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
     74   1.1  mrg {
     75   1.1  mrg   unsigned int n;
     76   1.1  mrg 
     77   1.5  mrg   if (state & BAR_WAS_LAST)
     78   1.1  mrg     {
     79   1.1  mrg       n = --bar->arrived;
     80   1.1  mrg       if (n > 0)
     81   1.1  mrg 	{
     82   1.1  mrg 	  do
     83   1.1  mrg 	    gomp_sem_post (&bar->sem1);
     84   1.1  mrg 	  while (--n != 0);
     85   1.1  mrg 	  gomp_sem_wait (&bar->sem2);
     86   1.1  mrg 	}
     87   1.1  mrg       gomp_mutex_unlock (&bar->mutex1);
     88   1.1  mrg     }
     89   1.1  mrg   else
     90   1.1  mrg     {
     91   1.1  mrg       gomp_mutex_unlock (&bar->mutex1);
     92   1.1  mrg       gomp_sem_wait (&bar->sem1);
     93   1.1  mrg 
     94   1.1  mrg #ifdef HAVE_SYNC_BUILTINS
     95   1.1  mrg       n = __sync_add_and_fetch (&bar->arrived, -1);
     96   1.1  mrg #else
     97   1.1  mrg       gomp_mutex_lock (&bar->mutex2);
     98   1.1  mrg       n = --bar->arrived;
     99   1.1  mrg       gomp_mutex_unlock (&bar->mutex2);
    100   1.1  mrg #endif
    101   1.1  mrg 
    102   1.1  mrg       if (n == 0)
    103   1.1  mrg 	gomp_sem_post (&bar->sem2);
    104   1.1  mrg     }
    105   1.1  mrg }
    106   1.1  mrg 
    107   1.1  mrg void
    108   1.1  mrg gomp_barrier_wait (gomp_barrier_t *barrier)
    109   1.1  mrg {
    110   1.1  mrg   gomp_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
    111   1.1  mrg }
    112   1.1  mrg 
    113   1.1  mrg void
    114   1.1  mrg gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
    115   1.1  mrg {
    116   1.1  mrg   unsigned int n;
    117   1.1  mrg 
    118   1.5  mrg   state &= ~BAR_CANCELLED;
    119   1.5  mrg   if (state & BAR_WAS_LAST)
    120   1.1  mrg     {
    121   1.1  mrg       n = --bar->arrived;
    122   1.1  mrg       struct gomp_thread *thr = gomp_thread ();
    123   1.1  mrg       struct gomp_team *team = thr->ts.team;
    124   1.1  mrg 
    125   1.5  mrg       team->work_share_cancelled = 0;
    126   1.1  mrg       if (team->task_count)
    127   1.1  mrg 	{
    128   1.1  mrg 	  gomp_barrier_handle_tasks (state);
    129   1.1  mrg 	  if (n > 0)
    130   1.1  mrg 	    gomp_sem_wait (&bar->sem2);
    131   1.1  mrg 	  gomp_mutex_unlock (&bar->mutex1);
    132   1.1  mrg 	  return;
    133   1.1  mrg 	}
    134   1.1  mrg 
    135   1.5  mrg       bar->generation = state + BAR_INCR - BAR_WAS_LAST;
    136   1.1  mrg       if (n > 0)
    137   1.1  mrg 	{
    138   1.1  mrg 	  do
    139   1.1  mrg 	    gomp_sem_post (&bar->sem1);
    140   1.1  mrg 	  while (--n != 0);
    141   1.1  mrg 	  gomp_sem_wait (&bar->sem2);
    142   1.1  mrg 	}
    143   1.1  mrg       gomp_mutex_unlock (&bar->mutex1);
    144   1.1  mrg     }
    145   1.1  mrg   else
    146   1.1  mrg     {
    147   1.1  mrg       gomp_mutex_unlock (&bar->mutex1);
    148   1.5  mrg       int gen;
    149   1.1  mrg       do
    150   1.1  mrg 	{
    151   1.1  mrg 	  gomp_sem_wait (&bar->sem1);
    152   1.5  mrg 	  gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    153   1.5  mrg 	  if (gen & BAR_TASK_PENDING)
    154   1.5  mrg 	    {
    155   1.5  mrg 	      gomp_barrier_handle_tasks (state);
    156   1.5  mrg 	      gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    157   1.5  mrg 	    }
    158   1.1  mrg 	}
    159   1.5  mrg       while (gen != state + BAR_INCR);
    160   1.1  mrg 
    161   1.1  mrg #ifdef HAVE_SYNC_BUILTINS
    162   1.1  mrg       n = __sync_add_and_fetch (&bar->arrived, -1);
    163   1.1  mrg #else
    164   1.1  mrg       gomp_mutex_lock (&bar->mutex2);
    165   1.1  mrg       n = --bar->arrived;
    166   1.1  mrg       gomp_mutex_unlock (&bar->mutex2);
    167   1.1  mrg #endif
    168   1.1  mrg 
    169   1.1  mrg       if (n == 0)
    170   1.1  mrg 	gomp_sem_post (&bar->sem2);
    171   1.1  mrg     }
    172   1.1  mrg }
    173   1.1  mrg 
    174   1.5  mrg bool
    175   1.5  mrg gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
    176   1.5  mrg 				   gomp_barrier_state_t state)
    177   1.5  mrg {
    178   1.5  mrg   unsigned int n;
    179   1.5  mrg 
    180   1.5  mrg   if (state & BAR_WAS_LAST)
    181   1.5  mrg     {
    182   1.5  mrg       bar->cancellable = false;
    183   1.5  mrg       n = --bar->arrived;
    184   1.5  mrg       struct gomp_thread *thr = gomp_thread ();
    185   1.5  mrg       struct gomp_team *team = thr->ts.team;
    186   1.5  mrg 
    187   1.5  mrg       team->work_share_cancelled = 0;
    188   1.5  mrg       if (team->task_count)
    189   1.5  mrg 	{
    190   1.5  mrg 	  gomp_barrier_handle_tasks (state);
    191   1.5  mrg 	  if (n > 0)
    192   1.5  mrg 	    gomp_sem_wait (&bar->sem2);
    193   1.5  mrg 	  gomp_mutex_unlock (&bar->mutex1);
    194   1.5  mrg 	  return false;
    195   1.5  mrg 	}
    196   1.5  mrg 
    197   1.5  mrg       bar->generation = state + BAR_INCR - BAR_WAS_LAST;
    198   1.5  mrg       if (n > 0)
    199   1.5  mrg 	{
    200   1.5  mrg 	  do
    201   1.5  mrg 	    gomp_sem_post (&bar->sem1);
    202   1.5  mrg 	  while (--n != 0);
    203   1.5  mrg 	  gomp_sem_wait (&bar->sem2);
    204   1.5  mrg 	}
    205   1.5  mrg       gomp_mutex_unlock (&bar->mutex1);
    206   1.5  mrg     }
    207   1.5  mrg   else
    208   1.5  mrg     {
    209   1.5  mrg       if (state & BAR_CANCELLED)
    210   1.5  mrg 	{
    211   1.5  mrg 	  gomp_mutex_unlock (&bar->mutex1);
    212   1.5  mrg 	  return true;
    213   1.5  mrg 	}
    214   1.5  mrg       bar->cancellable = true;
    215   1.5  mrg       gomp_mutex_unlock (&bar->mutex1);
    216   1.5  mrg       int gen;
    217   1.5  mrg       do
    218   1.5  mrg 	{
    219   1.5  mrg 	  gomp_sem_wait (&bar->sem1);
    220   1.5  mrg 	  gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    221   1.5  mrg 	  if (gen & BAR_CANCELLED)
    222   1.5  mrg 	    break;
    223   1.5  mrg 	  if (gen & BAR_TASK_PENDING)
    224   1.5  mrg 	    {
    225   1.5  mrg 	      gomp_barrier_handle_tasks (state);
    226   1.5  mrg 	      gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    227   1.5  mrg 	      if (gen & BAR_CANCELLED)
    228   1.5  mrg 		break;
    229   1.5  mrg 	    }
    230   1.5  mrg 	}
    231   1.5  mrg       while (gen != state + BAR_INCR);
    232   1.5  mrg 
    233   1.5  mrg #ifdef HAVE_SYNC_BUILTINS
    234   1.5  mrg       n = __sync_add_and_fetch (&bar->arrived, -1);
    235   1.5  mrg #else
    236   1.5  mrg       gomp_mutex_lock (&bar->mutex2);
    237   1.5  mrg       n = --bar->arrived;
    238   1.5  mrg       gomp_mutex_unlock (&bar->mutex2);
    239   1.5  mrg #endif
    240   1.5  mrg 
    241   1.5  mrg       if (n == 0)
    242   1.5  mrg 	gomp_sem_post (&bar->sem2);
    243   1.5  mrg       if (gen & BAR_CANCELLED)
    244   1.5  mrg 	return true;
    245   1.5  mrg     }
    246   1.5  mrg   return false;
    247   1.5  mrg }
    248   1.5  mrg 
    249   1.1  mrg void
    250   1.1  mrg gomp_team_barrier_wait (gomp_barrier_t *barrier)
    251   1.1  mrg {
    252   1.1  mrg   gomp_team_barrier_wait_end (barrier, gomp_barrier_wait_start (barrier));
    253   1.1  mrg }
    254   1.1  mrg 
    255   1.1  mrg void
    256   1.1  mrg gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
    257   1.1  mrg {
    258   1.1  mrg   if (count == 0)
    259   1.1  mrg     count = bar->total - 1;
    260   1.1  mrg   while (count-- > 0)
    261   1.1  mrg     gomp_sem_post (&bar->sem1);
    262   1.1  mrg }
    263   1.5  mrg 
    264   1.5  mrg bool
    265   1.5  mrg gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
    266   1.5  mrg {
    267   1.5  mrg   gomp_barrier_state_t state = gomp_barrier_wait_cancel_start (bar);
    268   1.5  mrg   return gomp_team_barrier_wait_cancel_end (bar, state);
    269   1.5  mrg }
    270   1.5  mrg 
    271   1.5  mrg void
    272   1.5  mrg gomp_team_barrier_cancel (struct gomp_team *team)
    273   1.5  mrg {
    274   1.5  mrg   if (team->barrier.generation & BAR_CANCELLED)
    275   1.5  mrg     return;
    276   1.5  mrg   gomp_mutex_lock (&team->barrier.mutex1);
    277   1.5  mrg   gomp_mutex_lock (&team->task_lock);
    278   1.5  mrg   if (team->barrier.generation & BAR_CANCELLED)
    279   1.5  mrg     {
    280   1.5  mrg       gomp_mutex_unlock (&team->task_lock);
    281   1.5  mrg       gomp_mutex_unlock (&team->barrier.mutex1);
    282   1.5  mrg       return;
    283   1.5  mrg     }
    284   1.5  mrg   team->barrier.generation |= BAR_CANCELLED;
    285   1.5  mrg   gomp_mutex_unlock (&team->task_lock);
    286   1.5  mrg   if (team->barrier.cancellable)
    287   1.5  mrg     {
    288   1.5  mrg       int n = team->barrier.arrived;
    289   1.5  mrg       if (n > 0)
    290   1.5  mrg 	{
    291   1.5  mrg 	  do
    292   1.5  mrg 	    gomp_sem_post (&team->barrier.sem1);
    293   1.5  mrg 	  while (--n != 0);
    294   1.5  mrg 	  gomp_sem_wait (&team->barrier.sem2);
    295   1.5  mrg 	}
    296   1.5  mrg       team->barrier.cancellable = false;
    297   1.5  mrg     }
    298   1.5  mrg   gomp_mutex_unlock (&team->barrier.mutex1);
    299   1.5  mrg }
    300