Home | History | Annotate | Line # | Download | only in rtems
      1  1.1.1.9  mrg /* Copyright (C) 2005-2024 Free Software Foundation, Inc.
      2      1.1  mrg    Contributed by Sebastian Huber <sebastian.huber (at) embedded-brains.de>.
      3      1.1  mrg 
      4      1.1  mrg    This file is part of the GNU OpenMP Library (libgomp).
      5      1.1  mrg 
      6      1.1  mrg    Libgomp is free software; you can redistribute it and/or modify it
      7      1.1  mrg    under the terms of the GNU General Public License as published by
      8      1.1  mrg    the Free Software Foundation; either version 3, or (at your option)
      9      1.1  mrg    any later version.
     10      1.1  mrg 
     11      1.1  mrg    Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
     12      1.1  mrg    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     13      1.1  mrg    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     14      1.1  mrg    more details.
     15      1.1  mrg 
     16      1.1  mrg    Under Section 7 of GPL version 3, you are granted additional
     17      1.1  mrg    permissions described in the GCC Runtime Library Exception, version
     18      1.1  mrg    3.1, as published by the Free Software Foundation.
     19      1.1  mrg 
     20      1.1  mrg    You should have received a copy of the GNU General Public License and
     21      1.1  mrg    a copy of the GCC Runtime Library Exception along with this program;
     22      1.1  mrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23      1.1  mrg    <http://www.gnu.org/licenses/>.  */
     24      1.1  mrg 
     25      1.1  mrg /* This is the RTEMS implementation of a barrier synchronization
     26      1.1  mrg    mechanism for libgomp.  It is identical to the Linux implementation, except
     27      1.1  mrg    that the futex API is slightly different.  This type is private to the
     28      1.1  mrg    library.  */
     29      1.1  mrg 
     30      1.1  mrg #ifndef GOMP_BARRIER_H
     31      1.1  mrg #define GOMP_BARRIER_H 1
     32      1.1  mrg 
     33      1.1  mrg #include <sys/lock.h>
     34      1.1  mrg 
     35      1.1  mrg typedef struct
     36      1.1  mrg {
     37      1.1  mrg   /* Make sure total/generation is in a mostly read cacheline, while
     38      1.1  mrg      awaited in a separate cacheline.  */
     39      1.1  mrg   unsigned total __attribute__((aligned (64)));
     40      1.1  mrg   unsigned generation;
     41      1.1  mrg   struct _Futex_Control futex;
     42      1.1  mrg   unsigned awaited __attribute__((aligned (64)));
     43      1.1  mrg   unsigned awaited_final;
     44      1.1  mrg } gomp_barrier_t;
     45      1.1  mrg 
     46      1.1  mrg typedef unsigned int gomp_barrier_state_t;
     47      1.1  mrg 
     48      1.1  mrg /* The generation field contains a counter in the high bits, with a few
     49      1.1  mrg    low bits dedicated to flags.  Note that TASK_PENDING and WAS_LAST can
     50      1.1  mrg    share space because WAS_LAST is never stored back to generation.  */
     51      1.1  mrg #define BAR_TASK_PENDING	1
     52      1.1  mrg #define BAR_WAS_LAST		1
     53      1.1  mrg #define BAR_WAITING_FOR_TASK	2
     54      1.1  mrg #define BAR_CANCELLED		4
     55      1.1  mrg #define BAR_INCR		8
     56      1.1  mrg 
     57      1.1  mrg static inline void gomp_barrier_init (gomp_barrier_t *bar, unsigned count)
     58      1.1  mrg {
     59      1.1  mrg   bar->total = count;
     60      1.1  mrg   bar->awaited = count;
     61      1.1  mrg   bar->awaited_final = count;
     62      1.1  mrg   bar->generation = 0;
     63      1.1  mrg   _Futex_Initialize (&bar->futex);
     64      1.1  mrg }
     65      1.1  mrg 
     66      1.1  mrg static inline void gomp_barrier_reinit (gomp_barrier_t *bar, unsigned count)
     67      1.1  mrg {
     68      1.1  mrg   __atomic_add_fetch (&bar->awaited, count - bar->total, MEMMODEL_ACQ_REL);
     69      1.1  mrg   bar->total = count;
     70      1.1  mrg }
     71      1.1  mrg 
     72      1.1  mrg static inline void gomp_barrier_destroy (gomp_barrier_t *bar)
     73      1.1  mrg {
     74      1.1  mrg }
     75      1.1  mrg 
     76      1.1  mrg extern void gomp_barrier_wait (gomp_barrier_t *);
     77      1.1  mrg extern void gomp_barrier_wait_last (gomp_barrier_t *);
     78      1.1  mrg extern void gomp_barrier_wait_end (gomp_barrier_t *, gomp_barrier_state_t);
     79      1.1  mrg extern void gomp_team_barrier_wait (gomp_barrier_t *);
     80      1.1  mrg extern void gomp_team_barrier_wait_final (gomp_barrier_t *);
     81      1.1  mrg extern void gomp_team_barrier_wait_end (gomp_barrier_t *,
     82      1.1  mrg 					gomp_barrier_state_t);
     83      1.1  mrg extern bool gomp_team_barrier_wait_cancel (gomp_barrier_t *);
     84      1.1  mrg extern bool gomp_team_barrier_wait_cancel_end (gomp_barrier_t *,
     85      1.1  mrg 					       gomp_barrier_state_t);
     86      1.1  mrg extern void gomp_team_barrier_wake (gomp_barrier_t *, int);
     87      1.1  mrg struct gomp_team;
     88      1.1  mrg extern void gomp_team_barrier_cancel (struct gomp_team *);
     89      1.1  mrg 
     90      1.1  mrg static inline gomp_barrier_state_t
     91      1.1  mrg gomp_barrier_wait_start (gomp_barrier_t *bar)
     92      1.1  mrg {
     93      1.1  mrg   unsigned int ret = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
     94      1.1  mrg   ret &= -BAR_INCR | BAR_CANCELLED;
     95      1.1  mrg   /* A memory barrier is needed before exiting from the various forms
     96      1.1  mrg      of gomp_barrier_wait, to satisfy OpenMP API version 3.1 section
     97      1.1  mrg      2.8.6 flush Construct, which says there is an implicit flush during
     98      1.1  mrg      a barrier region.  This is a convenient place to add the barrier,
     99      1.1  mrg      so we use MEMMODEL_ACQ_REL here rather than MEMMODEL_ACQUIRE.  */
    100      1.1  mrg   if (__atomic_add_fetch (&bar->awaited, -1, MEMMODEL_ACQ_REL) == 0)
    101      1.1  mrg     ret |= BAR_WAS_LAST;
    102      1.1  mrg   return ret;
    103      1.1  mrg }
    104      1.1  mrg 
    105      1.1  mrg static inline gomp_barrier_state_t
    106      1.1  mrg gomp_barrier_wait_cancel_start (gomp_barrier_t *bar)
    107      1.1  mrg {
    108      1.1  mrg   return gomp_barrier_wait_start (bar);
    109      1.1  mrg }
    110      1.1  mrg 
    111      1.1  mrg /* This is like gomp_barrier_wait_start, except it decrements
    112      1.1  mrg    bar->awaited_final rather than bar->awaited and should be used
    113      1.1  mrg    for the gomp_team_end barrier only.  */
    114      1.1  mrg static inline gomp_barrier_state_t
    115      1.1  mrg gomp_barrier_wait_final_start (gomp_barrier_t *bar)
    116      1.1  mrg {
    117      1.1  mrg   unsigned int ret = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
    118      1.1  mrg   ret &= -BAR_INCR | BAR_CANCELLED;
    119      1.1  mrg   /* See above gomp_barrier_wait_start comment.  */
    120      1.1  mrg   if (__atomic_add_fetch (&bar->awaited_final, -1, MEMMODEL_ACQ_REL) == 0)
    121      1.1  mrg     ret |= BAR_WAS_LAST;
    122      1.1  mrg   return ret;
    123      1.1  mrg }
    124      1.1  mrg 
    125      1.1  mrg static inline bool
    126      1.1  mrg gomp_barrier_last_thread (gomp_barrier_state_t state)
    127      1.1  mrg {
    128      1.1  mrg   return state & BAR_WAS_LAST;
    129      1.1  mrg }
    130      1.1  mrg 
    131      1.1  mrg /* All the inlines below must be called with team->task_lock
    132      1.1  mrg    held.  */
    133      1.1  mrg 
    134      1.1  mrg static inline void
    135      1.1  mrg gomp_team_barrier_set_task_pending (gomp_barrier_t *bar)
    136      1.1  mrg {
    137      1.1  mrg   bar->generation |= BAR_TASK_PENDING;
    138      1.1  mrg }
    139      1.1  mrg 
    140      1.1  mrg static inline void
    141      1.1  mrg gomp_team_barrier_clear_task_pending (gomp_barrier_t *bar)
    142      1.1  mrg {
    143      1.1  mrg   bar->generation &= ~BAR_TASK_PENDING;
    144      1.1  mrg }
    145      1.1  mrg 
    146      1.1  mrg static inline void
    147      1.1  mrg gomp_team_barrier_set_waiting_for_tasks (gomp_barrier_t *bar)
    148      1.1  mrg {
    149      1.1  mrg   bar->generation |= BAR_WAITING_FOR_TASK;
    150      1.1  mrg }
    151      1.1  mrg 
    152      1.1  mrg static inline bool
    153      1.1  mrg gomp_team_barrier_waiting_for_tasks (gomp_barrier_t *bar)
    154      1.1  mrg {
    155      1.1  mrg   return (bar->generation & BAR_WAITING_FOR_TASK) != 0;
    156      1.1  mrg }
    157      1.1  mrg 
    158      1.1  mrg static inline bool
    159      1.1  mrg gomp_team_barrier_cancelled (gomp_barrier_t *bar)
    160      1.1  mrg {
    161      1.1  mrg   return __builtin_expect ((bar->generation & BAR_CANCELLED) != 0, 0);
    162      1.1  mrg }
    163      1.1  mrg 
    164      1.1  mrg static inline void
    165      1.1  mrg gomp_team_barrier_done (gomp_barrier_t *bar, gomp_barrier_state_t state)
    166      1.1  mrg {
    167      1.1  mrg   bar->generation = (state & -BAR_INCR) + BAR_INCR;
    168      1.1  mrg }
    169      1.1  mrg 
    170      1.1  mrg #endif /* GOMP_BARRIER_H */
    171