1*38fd1498Szrj /* Copyright (C) 2005-2018 Free Software Foundation, Inc.
2*38fd1498Szrj Contributed by Richard Henderson <rth@redhat.com>.
3*38fd1498Szrj
4*38fd1498Szrj This file is part of the GNU Offloading and Multi Processing Library
5*38fd1498Szrj (libgomp).
6*38fd1498Szrj
7*38fd1498Szrj Libgomp is free software; you can redistribute it and/or modify it
8*38fd1498Szrj under the terms of the GNU General Public License as published by
9*38fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
10*38fd1498Szrj any later version.
11*38fd1498Szrj
12*38fd1498Szrj Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14*38fd1498Szrj FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15*38fd1498Szrj more details.
16*38fd1498Szrj
17*38fd1498Szrj Under Section 7 of GPL version 3, you are granted additional
18*38fd1498Szrj permissions described in the GCC Runtime Library Exception, version
19*38fd1498Szrj 3.1, as published by the Free Software Foundation.
20*38fd1498Szrj
21*38fd1498Szrj You should have received a copy of the GNU General Public License and
22*38fd1498Szrj a copy of the GCC Runtime Library Exception along with this program;
23*38fd1498Szrj see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24*38fd1498Szrj <http://www.gnu.org/licenses/>. */
25*38fd1498Szrj
26*38fd1498Szrj /* This file handles the SECTIONS construct. */
27*38fd1498Szrj
28*38fd1498Szrj #include "libgomp.h"
29*38fd1498Szrj
30*38fd1498Szrj
31*38fd1498Szrj /* Initialize the given work share construct from the given arguments. */
32*38fd1498Szrj
33*38fd1498Szrj static inline void
gomp_sections_init(struct gomp_work_share * ws,unsigned count)34*38fd1498Szrj gomp_sections_init (struct gomp_work_share *ws, unsigned count)
35*38fd1498Szrj {
36*38fd1498Szrj ws->sched = GFS_DYNAMIC;
37*38fd1498Szrj ws->chunk_size = 1;
38*38fd1498Szrj ws->end = count + 1L;
39*38fd1498Szrj ws->incr = 1;
40*38fd1498Szrj ws->next = 1;
41*38fd1498Szrj #ifdef HAVE_SYNC_BUILTINS
42*38fd1498Szrj /* Prepare things to make each iteration faster. */
43*38fd1498Szrj if (sizeof (long) > sizeof (unsigned))
44*38fd1498Szrj ws->mode = 1;
45*38fd1498Szrj else
46*38fd1498Szrj {
47*38fd1498Szrj struct gomp_thread *thr = gomp_thread ();
48*38fd1498Szrj struct gomp_team *team = thr->ts.team;
49*38fd1498Szrj long nthreads = team ? team->nthreads : 1;
50*38fd1498Szrj
51*38fd1498Szrj ws->mode = ((nthreads | ws->end)
52*38fd1498Szrj < 1UL << (sizeof (long) * __CHAR_BIT__ / 2 - 1));
53*38fd1498Szrj }
54*38fd1498Szrj #else
55*38fd1498Szrj ws->mode = 0;
56*38fd1498Szrj #endif
57*38fd1498Szrj }
58*38fd1498Szrj
59*38fd1498Szrj /* This routine is called when first encountering a sections construct
60*38fd1498Szrj that is not bound directly to a parallel construct. The first thread
61*38fd1498Szrj that arrives will create the work-share construct; subsequent threads
62*38fd1498Szrj will see the construct exists and allocate work from it.
63*38fd1498Szrj
64*38fd1498Szrj COUNT is the number of sections in this construct.
65*38fd1498Szrj
66*38fd1498Szrj Returns the 1-based section number for this thread to perform, or 0 if
67*38fd1498Szrj all work was assigned to other threads prior to this thread's arrival. */
68*38fd1498Szrj
69*38fd1498Szrj unsigned
GOMP_sections_start(unsigned count)70*38fd1498Szrj GOMP_sections_start (unsigned count)
71*38fd1498Szrj {
72*38fd1498Szrj struct gomp_thread *thr = gomp_thread ();
73*38fd1498Szrj long s, e, ret;
74*38fd1498Szrj
75*38fd1498Szrj if (gomp_work_share_start (false))
76*38fd1498Szrj {
77*38fd1498Szrj gomp_sections_init (thr->ts.work_share, count);
78*38fd1498Szrj gomp_work_share_init_done ();
79*38fd1498Szrj }
80*38fd1498Szrj
81*38fd1498Szrj #ifdef HAVE_SYNC_BUILTINS
82*38fd1498Szrj if (gomp_iter_dynamic_next (&s, &e))
83*38fd1498Szrj ret = s;
84*38fd1498Szrj else
85*38fd1498Szrj ret = 0;
86*38fd1498Szrj #else
87*38fd1498Szrj gomp_mutex_lock (&thr->ts.work_share->lock);
88*38fd1498Szrj if (gomp_iter_dynamic_next_locked (&s, &e))
89*38fd1498Szrj ret = s;
90*38fd1498Szrj else
91*38fd1498Szrj ret = 0;
92*38fd1498Szrj gomp_mutex_unlock (&thr->ts.work_share->lock);
93*38fd1498Szrj #endif
94*38fd1498Szrj
95*38fd1498Szrj return ret;
96*38fd1498Szrj }
97*38fd1498Szrj
98*38fd1498Szrj /* This routine is called when the thread completes processing of the
99*38fd1498Szrj section currently assigned to it. If the work-share construct is
100*38fd1498Szrj bound directly to a parallel construct, then the construct may have
101*38fd1498Szrj been set up before the parallel. In which case, this may be the
102*38fd1498Szrj first iteration for the thread.
103*38fd1498Szrj
104*38fd1498Szrj Returns the 1-based section number for this thread to perform, or 0 if
105*38fd1498Szrj all work was assigned to other threads prior to this thread's arrival. */
106*38fd1498Szrj
107*38fd1498Szrj unsigned
GOMP_sections_next(void)108*38fd1498Szrj GOMP_sections_next (void)
109*38fd1498Szrj {
110*38fd1498Szrj long s, e, ret;
111*38fd1498Szrj
112*38fd1498Szrj #ifdef HAVE_SYNC_BUILTINS
113*38fd1498Szrj if (gomp_iter_dynamic_next (&s, &e))
114*38fd1498Szrj ret = s;
115*38fd1498Szrj else
116*38fd1498Szrj ret = 0;
117*38fd1498Szrj #else
118*38fd1498Szrj struct gomp_thread *thr = gomp_thread ();
119*38fd1498Szrj
120*38fd1498Szrj gomp_mutex_lock (&thr->ts.work_share->lock);
121*38fd1498Szrj if (gomp_iter_dynamic_next_locked (&s, &e))
122*38fd1498Szrj ret = s;
123*38fd1498Szrj else
124*38fd1498Szrj ret = 0;
125*38fd1498Szrj gomp_mutex_unlock (&thr->ts.work_share->lock);
126*38fd1498Szrj #endif
127*38fd1498Szrj
128*38fd1498Szrj return ret;
129*38fd1498Szrj }
130*38fd1498Szrj
131*38fd1498Szrj /* This routine pre-initializes a work-share construct to avoid one
132*38fd1498Szrj synchronization once we get into the loop. */
133*38fd1498Szrj
134*38fd1498Szrj void
GOMP_parallel_sections_start(void (* fn)(void *),void * data,unsigned num_threads,unsigned count)135*38fd1498Szrj GOMP_parallel_sections_start (void (*fn) (void *), void *data,
136*38fd1498Szrj unsigned num_threads, unsigned count)
137*38fd1498Szrj {
138*38fd1498Szrj struct gomp_team *team;
139*38fd1498Szrj
140*38fd1498Szrj num_threads = gomp_resolve_num_threads (num_threads, count);
141*38fd1498Szrj team = gomp_new_team (num_threads);
142*38fd1498Szrj gomp_sections_init (&team->work_shares[0], count);
143*38fd1498Szrj gomp_team_start (fn, data, num_threads, 0, team);
144*38fd1498Szrj }
145*38fd1498Szrj
ialias_redirect(GOMP_parallel_end)146*38fd1498Szrj ialias_redirect (GOMP_parallel_end)
147*38fd1498Szrj
148*38fd1498Szrj void
149*38fd1498Szrj GOMP_parallel_sections (void (*fn) (void *), void *data,
150*38fd1498Szrj unsigned num_threads, unsigned count, unsigned flags)
151*38fd1498Szrj {
152*38fd1498Szrj struct gomp_team *team;
153*38fd1498Szrj
154*38fd1498Szrj num_threads = gomp_resolve_num_threads (num_threads, count);
155*38fd1498Szrj team = gomp_new_team (num_threads);
156*38fd1498Szrj gomp_sections_init (&team->work_shares[0], count);
157*38fd1498Szrj gomp_team_start (fn, data, num_threads, flags, team);
158*38fd1498Szrj fn (data);
159*38fd1498Szrj GOMP_parallel_end ();
160*38fd1498Szrj }
161*38fd1498Szrj
162*38fd1498Szrj /* The GOMP_section_end* routines are called after the thread is told
163*38fd1498Szrj that all sections are complete. The first two versions synchronize
164*38fd1498Szrj all threads; the nowait version does not. */
165*38fd1498Szrj
166*38fd1498Szrj void
GOMP_sections_end(void)167*38fd1498Szrj GOMP_sections_end (void)
168*38fd1498Szrj {
169*38fd1498Szrj gomp_work_share_end ();
170*38fd1498Szrj }
171*38fd1498Szrj
172*38fd1498Szrj bool
GOMP_sections_end_cancel(void)173*38fd1498Szrj GOMP_sections_end_cancel (void)
174*38fd1498Szrj {
175*38fd1498Szrj return gomp_work_share_end_cancel ();
176*38fd1498Szrj }
177*38fd1498Szrj
178*38fd1498Szrj void
GOMP_sections_end_nowait(void)179*38fd1498Szrj GOMP_sections_end_nowait (void)
180*38fd1498Szrj {
181*38fd1498Szrj gomp_work_share_end_nowait ();
182*38fd1498Szrj }
183