1171831Skan/* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
2169695Skan   Contributed by Richard Henderson <rth@redhat.com>.
3169695Skan
4169695Skan   This file is part of the GNU OpenMP Library (libgomp).
5169695Skan
6169695Skan   Libgomp is free software; you can redistribute it and/or modify it
7169695Skan   under the terms of the GNU Lesser General Public License as published by
8169695Skan   the Free Software Foundation; either version 2.1 of the License, or
9169695Skan   (at your option) any later version.
10169695Skan
11169695Skan   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12169695Skan   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13169695Skan   FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
14169695Skan   more details.
15169695Skan
16169695Skan   You should have received a copy of the GNU Lesser General Public License
17169695Skan   along with libgomp; see the file COPYING.LIB.  If not, write to the
18169695Skan   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19169695Skan   MA 02110-1301, USA.  */
20169695Skan
21169695Skan/* As a special exception, if you link this library with other files, some
22169695Skan   of which are compiled with GCC, to produce an executable, this library
23169695Skan   does not by itself cause the resulting executable to be covered by the
24169695Skan   GNU General Public License.  This exception does not however invalidate
25169695Skan   any other reasons why the executable file might be covered by the GNU
26169695Skan   General Public License.  */
27169695Skan
28169695Skan/* This file handles the SECTIONS construct.  */
29169695Skan
30169695Skan#include "libgomp.h"
31169695Skan
32169695Skan
33169695Skan/* Initialize the given work share construct from the given arguments.  */
34169695Skan
35169695Skanstatic inline void
36169695Skangomp_sections_init (struct gomp_work_share *ws, unsigned count)
37169695Skan{
38169695Skan  ws->sched = GFS_DYNAMIC;
39169695Skan  ws->chunk_size = 1;
40169695Skan  ws->end = count + 1;
41169695Skan  ws->incr = 1;
42169695Skan  ws->next = 1;
43169695Skan}
44169695Skan
45169695Skan/* This routine is called when first encountering a sections construct
46169695Skan   that is not bound directly to a parallel construct.  The first thread
47169695Skan   that arrives will create the work-share construct; subsequent threads
48169695Skan   will see the construct exists and allocate work from it.
49169695Skan
50169695Skan   COUNT is the number of sections in this construct.
51169695Skan
52169695Skan   Returns the 1-based section number for this thread to perform, or 0 if
53169695Skan   all work was assigned to other threads prior to this thread's arrival.  */
54169695Skan
55169695Skanunsigned
56169695SkanGOMP_sections_start (unsigned count)
57169695Skan{
58169695Skan  struct gomp_thread *thr = gomp_thread ();
59169695Skan  long s, e, ret;
60169695Skan
61169695Skan  if (gomp_work_share_start (false))
62169695Skan    gomp_sections_init (thr->ts.work_share, count);
63169695Skan
64169695Skan  if (gomp_iter_dynamic_next_locked (&s, &e))
65169695Skan    ret = s;
66169695Skan  else
67169695Skan    ret = 0;
68169695Skan
69169695Skan  gomp_mutex_unlock (&thr->ts.work_share->lock);
70169695Skan
71169695Skan  return ret;
72169695Skan}
73169695Skan
74169695Skan/* This routine is called when the thread completes processing of the
75169695Skan   section currently assigned to it.  If the work-share construct is
76169695Skan   bound directly to a parallel construct, then the construct may have
77169695Skan   been set up before the parallel.  In which case, this may be the
78169695Skan   first iteration for the thread.
79169695Skan
80169695Skan   Returns the 1-based section number for this thread to perform, or 0 if
81169695Skan   all work was assigned to other threads prior to this thread's arrival.  */
82169695Skan
83169695Skanunsigned
84169695SkanGOMP_sections_next (void)
85169695Skan{
86169695Skan  struct gomp_thread *thr = gomp_thread ();
87169695Skan  long s, e, ret;
88169695Skan
89169695Skan  gomp_mutex_lock (&thr->ts.work_share->lock);
90169695Skan  if (gomp_iter_dynamic_next_locked (&s, &e))
91169695Skan    ret = s;
92169695Skan  else
93169695Skan    ret = 0;
94169695Skan  gomp_mutex_unlock (&thr->ts.work_share->lock);
95169695Skan
96169695Skan  return ret;
97169695Skan}
98169695Skan
99169695Skan/* This routine pre-initializes a work-share construct to avoid one
100169695Skan   synchronization once we get into the loop.  */
101169695Skan
102169695Skanvoid
103169695SkanGOMP_parallel_sections_start (void (*fn) (void *), void *data,
104169695Skan			      unsigned num_threads, unsigned count)
105169695Skan{
106169695Skan  struct gomp_work_share *ws;
107169695Skan
108169695Skan  num_threads = gomp_resolve_num_threads (num_threads);
109171831Skan  if (gomp_dyn_var && num_threads > count)
110169695Skan    num_threads = count;
111169695Skan
112169695Skan  ws = gomp_new_work_share (false, num_threads);
113169695Skan  gomp_sections_init (ws, count);
114169695Skan  gomp_team_start (fn, data, num_threads, ws);
115169695Skan}
116169695Skan
117169695Skan/* The GOMP_section_end* routines are called after the thread is told
118169695Skan   that all sections are complete.  This first version synchronizes
119169695Skan   all threads; the nowait version does not.  */
120169695Skan
121169695Skanvoid
122169695SkanGOMP_sections_end (void)
123169695Skan{
124169695Skan  gomp_work_share_end ();
125169695Skan}
126169695Skan
127169695Skanvoid
128169695SkanGOMP_sections_end_nowait (void)
129169695Skan{
130169695Skan  gomp_work_share_end_nowait ();
131169695Skan}
132