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 #ifndef GOMP_BARRIER_H
     32   1.1  mrg #define GOMP_BARRIER_H 1
     33   1.1  mrg 
     34   1.1  mrg #include <pthread.h>
     35   1.1  mrg 
     36   1.1  mrg typedef struct
     37   1.1  mrg {
     38   1.1  mrg   gomp_mutex_t mutex1;
     39   1.1  mrg #ifndef HAVE_SYNC_BUILTINS
     40   1.1  mrg   gomp_mutex_t mutex2;
     41   1.1  mrg #endif
     42   1.1  mrg   gomp_sem_t sem1;
     43   1.1  mrg   gomp_sem_t sem2;
     44   1.1  mrg   unsigned total;
     45   1.1  mrg   unsigned arrived;
     46   1.1  mrg   unsigned generation;
     47   1.5  mrg   bool cancellable;
     48   1.1  mrg } gomp_barrier_t;
     49   1.5  mrg 
     50   1.1  mrg typedef unsigned int gomp_barrier_state_t;
     51   1.1  mrg 
     52   1.5  mrg /* The generation field contains a counter in the high bits, with a few
     53   1.5  mrg    low bits dedicated to flags.  Note that TASK_PENDING and WAS_LAST can
     54   1.5  mrg    share space because WAS_LAST is never stored back to generation.  */
     55   1.5  mrg #define BAR_TASK_PENDING	1
     56   1.5  mrg #define BAR_WAS_LAST		1
     57   1.5  mrg #define BAR_WAITING_FOR_TASK	2
     58   1.5  mrg #define BAR_CANCELLED		4
     59   1.5  mrg #define BAR_INCR		8
     60   1.5  mrg 
     61   1.1  mrg extern void gomp_barrier_init (gomp_barrier_t *, unsigned);
     62   1.1  mrg extern void gomp_barrier_reinit (gomp_barrier_t *, unsigned);
     63   1.1  mrg extern void gomp_barrier_destroy (gomp_barrier_t *);
     64   1.1  mrg 
     65   1.1  mrg extern void gomp_barrier_wait (gomp_barrier_t *);
     66   1.1  mrg extern void gomp_barrier_wait_end (gomp_barrier_t *, gomp_barrier_state_t);
     67   1.1  mrg extern void gomp_team_barrier_wait (gomp_barrier_t *);
     68   1.1  mrg extern void gomp_team_barrier_wait_end (gomp_barrier_t *,
     69   1.1  mrg 					gomp_barrier_state_t);
     70   1.5  mrg extern bool gomp_team_barrier_wait_cancel (gomp_barrier_t *);
     71   1.5  mrg extern bool gomp_team_barrier_wait_cancel_end (gomp_barrier_t *,
     72   1.5  mrg 					       gomp_barrier_state_t);
     73   1.1  mrg extern void gomp_team_barrier_wake (gomp_barrier_t *, int);
     74   1.5  mrg struct gomp_team;
     75   1.5  mrg extern void gomp_team_barrier_cancel (struct gomp_team *);
     76   1.1  mrg 
     77   1.1  mrg static inline gomp_barrier_state_t
     78   1.1  mrg gomp_barrier_wait_start (gomp_barrier_t *bar)
     79   1.1  mrg {
     80   1.1  mrg   unsigned int ret;
     81   1.1  mrg   gomp_mutex_lock (&bar->mutex1);
     82   1.5  mrg   ret = bar->generation & (-BAR_INCR | BAR_CANCELLED);
     83   1.5  mrg   if (++bar->arrived == bar->total)
     84   1.5  mrg     ret |= BAR_WAS_LAST;
     85   1.5  mrg   return ret;
     86   1.5  mrg }
     87   1.5  mrg 
     88   1.5  mrg static inline gomp_barrier_state_t
     89   1.5  mrg gomp_barrier_wait_cancel_start (gomp_barrier_t *bar)
     90   1.5  mrg {
     91   1.5  mrg   unsigned int ret;
     92   1.5  mrg   gomp_mutex_lock (&bar->mutex1);
     93   1.5  mrg   ret = bar->generation & (-BAR_INCR | BAR_CANCELLED);
     94   1.5  mrg   if (ret & BAR_CANCELLED)
     95   1.5  mrg     return ret;
     96   1.5  mrg   if (++bar->arrived == bar->total)
     97   1.5  mrg     ret |= BAR_WAS_LAST;
     98   1.1  mrg   return ret;
     99   1.1  mrg }
    100   1.1  mrg 
    101   1.5  mrg static inline void
    102   1.5  mrg gomp_team_barrier_wait_final (gomp_barrier_t *bar)
    103   1.5  mrg {
    104   1.5  mrg   gomp_team_barrier_wait (bar);
    105   1.5  mrg }
    106   1.5  mrg 
    107   1.1  mrg static inline bool
    108   1.1  mrg gomp_barrier_last_thread (gomp_barrier_state_t state)
    109   1.1  mrg {
    110   1.5  mrg   return state & BAR_WAS_LAST;
    111   1.1  mrg }
    112   1.1  mrg 
    113   1.1  mrg static inline void
    114   1.1  mrg gomp_barrier_wait_last (gomp_barrier_t *bar)
    115   1.1  mrg {
    116   1.1  mrg   gomp_barrier_wait (bar);
    117   1.1  mrg }
    118   1.1  mrg 
    119   1.1  mrg /* All the inlines below must be called with team->task_lock
    120   1.1  mrg    held.  */
    121   1.1  mrg 
    122   1.1  mrg static inline void
    123   1.1  mrg gomp_team_barrier_set_task_pending (gomp_barrier_t *bar)
    124   1.1  mrg {
    125   1.5  mrg   bar->generation |= BAR_TASK_PENDING;
    126   1.1  mrg }
    127   1.1  mrg 
    128   1.1  mrg static inline void
    129   1.1  mrg gomp_team_barrier_clear_task_pending (gomp_barrier_t *bar)
    130   1.1  mrg {
    131   1.5  mrg   bar->generation &= ~BAR_TASK_PENDING;
    132   1.1  mrg }
    133   1.1  mrg 
    134   1.1  mrg static inline void
    135   1.1  mrg gomp_team_barrier_set_waiting_for_tasks (gomp_barrier_t *bar)
    136   1.1  mrg {
    137   1.5  mrg   bar->generation |= BAR_WAITING_FOR_TASK;
    138   1.1  mrg }
    139   1.1  mrg 
    140   1.1  mrg static inline bool
    141   1.1  mrg gomp_team_barrier_waiting_for_tasks (gomp_barrier_t *bar)
    142   1.1  mrg {
    143   1.5  mrg   return (bar->generation & BAR_WAITING_FOR_TASK) != 0;
    144   1.5  mrg }
    145   1.5  mrg 
    146   1.5  mrg static inline bool
    147   1.5  mrg gomp_team_barrier_cancelled (gomp_barrier_t *bar)
    148   1.5  mrg {
    149   1.5  mrg   return __builtin_expect ((bar->generation & BAR_CANCELLED) != 0, 0);
    150   1.1  mrg }
    151   1.1  mrg 
    152   1.1  mrg static inline void
    153   1.1  mrg gomp_team_barrier_done (gomp_barrier_t *bar, gomp_barrier_state_t state)
    154   1.1  mrg {
    155   1.5  mrg   bar->generation = (state & -BAR_INCR) + BAR_INCR;
    156   1.1  mrg }
    157   1.1  mrg 
    158   1.1  mrg #endif /* GOMP_BARRIER_H */
    159