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